RuntimeEnvironment.java revision 816
30N/A/*
30N/A * CDDL HEADER START
30N/A *
30N/A * The contents of this file are subject to the terms of the
30N/A * Common Development and Distribution License (the "License").
30N/A * You may not use this file except in compliance with the License.
30N/A *
30N/A * See LICENSE.txt included in this distribution for the specific
30N/A * language governing permissions and limitations under the License.
30N/A *
30N/A * When distributing Covered Code, include this CDDL HEADER in each
30N/A * file and include the License file at LICENSE.txt.
30N/A * If applicable, add the following below this CDDL HEADER, with the
30N/A * fields enclosed by brackets "[]" replaced with your own identifying
30N/A * information: Portions Copyright [yyyy] [name of copyright owner]
30N/A *
30N/A * CDDL HEADER END
30N/A */
30N/A
30N/A/*
30N/A * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
30N/A * Use is subject to license terms.
30N/A */
30N/Apackage org.opensolaris.opengrok.configuration;
30N/A
58N/Aimport java.beans.XMLDecoder;
58N/Aimport java.beans.XMLEncoder;
58N/Aimport java.io.BufferedInputStream;
30N/Aimport java.io.File;
30N/Aimport java.io.IOException;
58N/Aimport java.net.InetAddress;
58N/Aimport java.net.ServerSocket;
58N/Aimport java.net.Socket;
58N/Aimport java.net.SocketAddress;
58N/Aimport java.net.UnknownHostException;
667N/Aimport java.util.Date;
58N/Aimport java.util.List;
320N/Aimport java.util.logging.Level;
320N/Aimport java.util.logging.Logger;
490N/Aimport org.opensolaris.opengrok.OpenGrokLogger;
664N/Aimport org.opensolaris.opengrok.history.HistoryGuru;
664N/Aimport org.opensolaris.opengrok.history.RepositoryInfo;
112N/Aimport org.opensolaris.opengrok.index.IgnoredNames;
570N/Aimport org.opensolaris.opengrok.util.Executor;
30N/A
30N/A/**
30N/A * The RuntimeEnvironment class is used as a placeholder for the current
58N/A * configuration this execution context (classloader) is using.
30N/A */
418N/Apublic final class RuntimeEnvironment {
58N/A private Configuration configuration;
456N/A private final ThreadLocal<Configuration> threadConfig;
30N/A
320N/A private static final Logger log = Logger.getLogger(RuntimeEnvironment.class.getName());
320N/A
30N/A private static RuntimeEnvironment instance = new RuntimeEnvironment();
30N/A
77N/A /**
77N/A * Get the one and only instance of the RuntimeEnvironment
77N/A * @return the one and only instance of the RuntimeEnvironment
77N/A */
30N/A public static RuntimeEnvironment getInstance() {
30N/A return instance;
30N/A }
30N/A
30N/A /**
77N/A * Creates a new instance of RuntimeEnvironment. Private to ensure a
77N/A * singleton pattern.
30N/A */
30N/A private RuntimeEnvironment() {
58N/A configuration = new Configuration();
145N/A threadConfig = new ThreadLocal<Configuration>() {
145N/A @Override protected Configuration initialValue() {
145N/A return configuration;
145N/A }
145N/A };
58N/A }
77N/A
490N/A private String getCanonicalPath(String s) {
490N/A try {
490N/A File file = new File(s);
490N/A if (!file.exists()) {
490N/A return s;
490N/A }
490N/A return file.getCanonicalPath();
490N/A } catch (IOException ex) {
490N/A OpenGrokLogger.getLogger().log(Level.SEVERE, "Failed to get canonical path", ex);
490N/A return s;
490N/A }
490N/A }
490N/A
77N/A /**
77N/A * Get the path to the where the index database is stored
77N/A * @return the path to the index database
77N/A */
58N/A public String getDataRootPath() {
145N/A return threadConfig.get().getDataRoot();
58N/A }
58N/A
77N/A /**
77N/A * Get a file representing the index database
77N/A * @return the index database
77N/A */
30N/A public File getDataRootFile() {
58N/A File ret = null;
58N/A String file = getDataRootPath();
58N/A if (file != null) {
58N/A ret = new File(file);
58N/A }
58N/A
58N/A return ret;
30N/A }
58N/A
77N/A /**
77N/A * Set the path to where the index database is stored
77N/A * @param dataRoot the index database
77N/A */
77N/A public void setDataRoot(String dataRoot) {
492N/A final File file = new File(dataRoot);
504N/A if (!file.exists() && !file.mkdirs()) {
504N/A OpenGrokLogger.getLogger().log(
504N/A Level.SEVERE, "Failed to create dataroot: " + dataRoot);
492N/A }
490N/A threadConfig.get().setDataRoot(getCanonicalPath(dataRoot));
77N/A }
77N/A
77N/A /**
77N/A * Get the path to where the sources are located
77N/A * @return path to where the sources are located
77N/A */
77N/A public String getSourceRootPath() {
145N/A return threadConfig.get().getSourceRoot();
77N/A }
77N/A
77N/A /**
77N/A * Get a file representing the directory where the sources are located
77N/A * @return A file representing the directory where the sources are located
77N/A */
30N/A public File getSourceRootFile() {
58N/A File ret = null;
58N/A String file = getSourceRootPath();
58N/A if (file != null) {
58N/A ret = new File(file);
58N/A }
58N/A
58N/A return ret;
58N/A }
58N/A
77N/A /**
77N/A * Specify the source root
77N/A * @param sourceRoot the location of the sources
77N/A */
58N/A public void setSourceRoot(String sourceRoot) {
490N/A threadConfig.get().setSourceRoot(getCanonicalPath(sourceRoot));
58N/A }
58N/A
77N/A /**
77N/A * Do we have projects?
77N/A * @return true if we have projects
77N/A */
58N/A public boolean hasProjects() {
58N/A List<Project> proj = getProjects();
456N/A return (proj != null && !proj.isEmpty());
58N/A }
58N/A
77N/A /**
77N/A * Get all of the projects
77N/A * @return a list containing all of the projects (may be null)
77N/A */
58N/A public List<Project> getProjects() {
145N/A return threadConfig.get().getProjects();
58N/A }
58N/A
77N/A /**
77N/A * Set the list of the projects
77N/A * @param projects the list of projects to use
77N/A */
58N/A public void setProjects(List<Project> projects) {
145N/A threadConfig.get().setProjects(projects);
58N/A }
58N/A
77N/A /**
77N/A * Register this thread in the thread/configuration map (so that all
77N/A * subsequent calls to the RuntimeEnvironment from this thread will use
77N/A * the same configuration
77N/A */
58N/A public void register() {
145N/A threadConfig.set(configuration);
58N/A }
58N/A
77N/A /**
77N/A * Get the context name of the web application
77N/A * @return the web applications context name
77N/A */
58N/A public String getUrlPrefix() {
145N/A return threadConfig.get().getUrlPrefix();
58N/A }
58N/A
77N/A /**
77N/A * Set the web context name
77N/A * @param urlPrefix the web applications context name
77N/A */
58N/A public void setUrlPrefix(String urlPrefix) {
145N/A threadConfig.get().setUrlPrefix(urlPrefix);
58N/A }
58N/A
77N/A /**
77N/A * Get the name of the ctags program in use
77N/A * @return the name of the ctags program in use
77N/A */
58N/A public String getCtags() {
145N/A return threadConfig.get().getCtags();
58N/A }
58N/A
77N/A /**
77N/A * Specify the CTags program to use
77N/A * @param ctags the ctags program to use
77N/A */
58N/A public void setCtags(String ctags) {
145N/A threadConfig.get().setCtags(ctags);
58N/A }
99N/A
816N/A public int getCachePages() {
816N/A return threadConfig.get().getCachePages();
816N/A }
816N/A
816N/A public void setCachePages(int cachePages) {
816N/A threadConfig.get().setCachePages(cachePages);
816N/A }
816N/A
816N/A public int getHitsPerPage() {
816N/A return threadConfig.get().getHitsPerPage();
816N/A }
816N/A
816N/A public void setHitsPerPage(int hitsPerPage) {
816N/A threadConfig.get().setHitsPerPage(hitsPerPage);
816N/A }
816N/A
99N/A /**
99N/A * Validate that I have a Exuberant ctags program I may use
99N/A * @return true if success, false otherwise
99N/A */
99N/A public boolean validateExuberantCtags() {
571N/A boolean ret = true;
571N/A Executor executor = new Executor(new String[] {getCtags(), "--version"});
570N/A
570N/A executor.exec(false);
570N/A String output = executor.getOutputString();
570N/A if (output == null || output.indexOf("Exuberant Ctags") == -1) {
570N/A log.severe("Error: No Exuberant Ctags found in PATH!\n" +
571N/A "(tried running " + getCtags() + ")\n" +
570N/A "Please use option -c to specify path to a good Exuberant Ctags program");
571N/A ret = false;
345N/A }
570N/A
571N/A return ret;
99N/A }
99N/A
77N/A /**
77N/A * Get the max time a SMC operation may use to avoid beeing cached
77N/A * @return the max time
77N/A */
58N/A public int getHistoryReaderTimeLimit() {
145N/A return threadConfig.get().getHistoryCacheTime();
58N/A }
58N/A
77N/A /**
77N/A * Specify the maximum time a SCM operation should take before it will
77N/A * be cached (in ms)
77N/A * @param historyReaderTimeLimit the max time in ms before it is cached
77N/A */
58N/A public void setHistoryReaderTimeLimit(int historyReaderTimeLimit) {
145N/A threadConfig.get().setHistoryCacheTime(historyReaderTimeLimit);
30N/A }
58N/A
77N/A /**
77N/A * Is history cache currently enabled?
77N/A * @return true if history cache is enabled
77N/A */
58N/A public boolean useHistoryCache() {
145N/A return threadConfig.get().isHistoryCache();
58N/A }
58N/A
77N/A /**
77N/A * Specify if we should use history cache or not
77N/A * @param useHistoryCache set false if you do not want to use history cache
77N/A */
58N/A public void setUseHistoryCache(boolean useHistoryCache) {
145N/A threadConfig.get().setHistoryCache(useHistoryCache);
58N/A }
773N/A
773N/A /**
773N/A * Should the history cache be stored in a database instead of in XML
773N/A * files?
773N/A *
773N/A * @return {@code true} if the cache should be stored in a database
773N/A */
773N/A public boolean storeHistoryCacheInDB() {
773N/A return threadConfig.get().isHistoryCacheInDB();
773N/A }
773N/A
773N/A /**
773N/A * Set whether the history cache should be stored in a database.
773N/A * @param store {@code true} if the cache should be stored in a database
773N/A */
773N/A public void setStoreHistoryCacheInDB(boolean store) {
773N/A threadConfig.get().setHistoryCacheInDB(store);
773N/A }
77N/A
77N/A /**
77N/A * Should we generate HTML or not during the indexing phase
77N/A * @return true if HTML should be generated during the indexing phase
77N/A */
65N/A public boolean isGenerateHtml() {
145N/A return threadConfig.get().isGenerateHtml();
65N/A }
65N/A
77N/A /**
77N/A * Specify if we should generate HTML or not during the indexing phase
77N/A * @param generateHtml set this to true to pregenerate HTML
77N/A */
65N/A public void setGenerateHtml(boolean generateHtml) {
145N/A threadConfig.get().setGenerateHtml(generateHtml);
65N/A }
58N/A
335N/A /**
335N/A * Set if we should compress the xref files or not
335N/A * @param compressXref set to true if the generated html files should be
335N/A * compressed
335N/A */
335N/A public void setCompressXref(boolean compressXref) {
335N/A threadConfig.get().setCompressXref(compressXref);
335N/A }
335N/A
335N/A /**
335N/A * Are we using copressed HTML files?
335N/A * @return true if the html-files should be compressed. false otherwise
335N/A */
335N/A public boolean isCompressXref() {
335N/A return threadConfig.get().isCompressXref();
335N/A }
335N/A
106N/A public boolean isQuickContextScan() {
145N/A return threadConfig.get().isQuickContextScan();
106N/A }
106N/A
106N/A public void setQuickContextScan(boolean quickContextScan) {
145N/A threadConfig.get().setQuickContextScan(quickContextScan);
106N/A }
665N/A
665N/A public List<RepositoryInfo> getRepositories() {
665N/A return threadConfig.get().getRepositories();
665N/A }
665N/A
77N/A /**
77N/A * Set the map of external SCM repositories
77N/A * @param repositories the repositories to use
77N/A */
664N/A public void setRepositories(List<RepositoryInfo> repositories) {
145N/A threadConfig.get().setRepositories(repositories);
58N/A }
58N/A
77N/A /**
77N/A * Set the project that is specified to be the default project to use. The
77N/A * default project is the project you will search (from the web application)
77N/A * if the page request didn't contain the cookie..
77N/A * @param defaultProject The default project to use
77N/A */
77N/A public void setDefaultProject(Project defaultProject) {
145N/A threadConfig.get().setDefaultProject(defaultProject);
58N/A }
58N/A
77N/A /**
77N/A * Get the project that is specified to be the default project to use. The
77N/A * default project is the project you will search (from the web application)
77N/A * if the page request didn't contain the cookie..
77N/A * @return the default project (may be null if not specified)
77N/A */
77N/A public Project getDefaultProject() {
145N/A return threadConfig.get().getDefaultProject();
77N/A }
77N/A
77N/A /**
99N/A * Chandan wrote the following answer on the opengrok-discuss list:
99N/A * "Traditionally search engines (specially spiders) think that large files
99N/A * are junk. Large files tend to be multimedia files etc., which text
99N/A * search spiders do not want to chew. So they ignore the contents of
99N/A * the file after a cutoff length. Lucene does this by number of words,
99N/A * which is by default is 10,000."
99N/A * By default OpenGrok will increase this limit to 60000, but it may be
99N/A * overridden in the configuration file
99N/A * @return The maximum words to index
99N/A */
99N/A public int getIndexWordLimit() {
145N/A return threadConfig.get().getIndexWordLimit();
99N/A }
99N/A
124N/A /**
124N/A * Set the number of words in a file Lucene will index.
124N/A * See getIndexWordLimit for a better description.
124N/A * @param indexWordLimit the number of words to index in a single file
124N/A */
99N/A public void setIndexWordLimit(int indexWordLimit) {
145N/A threadConfig.get().setIndexWordLimit(indexWordLimit);
99N/A }
99N/A
124N/A /**
124N/A * Is the verbosity flag turned on?
124N/A * @return true if we can print extra information
124N/A */
99N/A public boolean isVerbose() {
145N/A return threadConfig.get().isVerbose();
99N/A }
124N/A
124N/A /**
124N/A * Set the verbosity flag (to add extra debug information in output)
124N/A * @param verbose new value
124N/A */
99N/A public void setVerbose(boolean verbose) {
145N/A threadConfig.get().setVerbose(verbose);
99N/A }
124N/A
125N/A /**
125N/A * Specify if a search may start with a wildcard. Note that queries
125N/A * that start with a wildcard will give a significant impact on the
125N/A * search performace.
125N/A * @param allowLeadingWildcard set to true to activate (disabled by default)
125N/A */
125N/A public void setAllowLeadingWildcard(boolean allowLeadingWildcard) {
145N/A threadConfig.get().setAllowLeadingWildcard(allowLeadingWildcard);
125N/A }
125N/A
125N/A /**
125N/A * Is leading wildcards allowed?
125N/A * @return true if a search may start with a wildcard
125N/A */
125N/A public boolean isAllowLeadingWildcard() {
145N/A return threadConfig.get().isAllowLeadingWildcard();
125N/A }
124N/A
112N/A public IgnoredNames getIgnoredNames() {
145N/A return threadConfig.get().getIgnoredNames();
112N/A }
112N/A
112N/A public void setIgnoredNames(IgnoredNames ignoredNames) {
145N/A threadConfig.get().setIgnoredNames(ignoredNames);
112N/A }
129N/A
129N/A /**
129N/A * Returns the user page for the history listing
129N/A * @return the URL string fragment preceeding the username
129N/A */
129N/A public String getUserPage() {
145N/A return threadConfig.get().getUserPage();
129N/A }
129N/A
129N/A /**
129N/A * Sets the user page for the history listing
129N/A * @param userPage the URL fragment preceeding the username from history
129N/A */
129N/A public void setUserPage(String userPage) {
145N/A threadConfig.get().setUserPage(userPage);
129N/A }
129N/A
129N/A /**
129N/A * Returns the bug page for the history listing
129N/A * @return the URL string fragment preceeding the bug ID
129N/A */
129N/A public String getBugPage() {
145N/A return threadConfig.get().getBugPage();
129N/A }
129N/A
129N/A /**
129N/A * Sets the bug page for the history listing
129N/A * @param bugPage the URL fragment preceeding the bug ID
129N/A */
129N/A public void setBugPage(String bugPage) {
145N/A threadConfig.get().setBugPage(bugPage);
129N/A }
129N/A
129N/A /**
129N/A * Returns the bug regex for the history listing
129N/A * @return the regex that is looked for in history comments
129N/A */
129N/A public String getBugPattern() {
145N/A return threadConfig.get().getBugPattern();
129N/A }
129N/A
129N/A /**
129N/A * Sets the bug regex for the history listing
129N/A * @param bugPattern the regex to search history comments
129N/A */
129N/A public void setBugPattern(String bugPattern) {
145N/A threadConfig.get().setBugPattern(bugPattern);
129N/A }
99N/A
318N/A
318N/A /**
318N/A * Returns the review(ARC) page for the history listing
318N/A * @return the URL string fragment preceeding the review page ID
318N/A */
318N/A public String getReviewPage() {
318N/A return threadConfig.get().getReviewPage();
318N/A }
318N/A
318N/A /**
318N/A * Sets the review(ARC) page for the history listing
318N/A * @param reviewPage the URL fragment preceeding the review page ID
318N/A */
318N/A public void setReviewPage(String reviewPage) {
318N/A threadConfig.get().setReviewPage(reviewPage);
318N/A }
318N/A
318N/A /**
318N/A * Returns the review(ARC) regex for the history listing
318N/A * @return the regex that is looked for in history comments
318N/A */
318N/A public String getReviewPattern() {
318N/A return threadConfig.get().getReviewPattern();
318N/A }
318N/A
318N/A /**
318N/A * Sets the review(ARC) regex for the history listing
318N/A * @param reviewPattern the regex to search history comments
318N/A */
318N/A public void setReviewPattern(String reviewPattern) {
318N/A threadConfig.get().setReviewPattern(reviewPattern);
318N/A }
318N/A
144N/A public String getWebappLAF() {
145N/A return threadConfig.get().getWebappLAF();
144N/A }
144N/A
144N/A public void setWebappLAF(String laf) {
145N/A threadConfig.get().setWebappLAF(laf);
144N/A }
173N/A
173N/A public boolean isRemoteScmSupported() {
173N/A return threadConfig.get().isRemoteScmSupported();
173N/A }
173N/A
173N/A public void setRemoteScmSupported(boolean supported) {
173N/A threadConfig.get().setRemoteScmSupported(supported);
173N/A }
173N/A
253N/A public boolean isOptimizeDatabase() {
253N/A return threadConfig.get().isOptimizeDatabase();
253N/A }
253N/A
253N/A public void setOptimizeDatabase(boolean optimizeDatabase) {
253N/A threadConfig.get().setOptimizeDatabase(optimizeDatabase);
253N/A }
253N/A
296N/A public boolean isUsingLuceneLocking() {
296N/A return threadConfig.get().isUsingLuceneLocking();
296N/A }
296N/A
296N/A public void setUsingLuceneLocking(boolean useLuceneLocking) {
430N/A threadConfig.get().setUsingLuceneLocking(useLuceneLocking);
296N/A }
296N/A
480N/A public boolean isIndexVersionedFilesOnly() {
480N/A return threadConfig.get().isIndexVersionedFilesOnly();
480N/A }
480N/A
480N/A public void setIndexVersionedFilesOnly(boolean indexVersionedFilesOnly) {
480N/A threadConfig.get().setIndexVersionedFilesOnly(indexVersionedFilesOnly);
480N/A }
480N/A
667N/A public Date getDateForLastIndexRun() {
667N/A return threadConfig.get().getDateForLastIndexRun();
667N/A }
667N/A
99N/A /**
77N/A * Read an configuration file and set it as the current configuration.
77N/A * @param file the file to read
77N/A * @throws IOException if an error occurs
77N/A */
58N/A public void readConfiguration(File file) throws IOException {
664N/A setConfiguration(Configuration.read(file));
58N/A }
58N/A
77N/A /**
77N/A * Write the current configuration to a file
77N/A * @param file the file to write the configuration into
77N/A * @throws IOException if an error occurs
77N/A */
58N/A public void writeConfiguration(File file) throws IOException {
234N/A threadConfig.get().write(file);
58N/A }
58N/A
77N/A /**
77N/A * Write the current configuration to a socket
77N/A * @param host the host address to receive the configuration
77N/A * @param port the port to use on the host
77N/A * @throws IOException if an error occurs
77N/A */
58N/A public void writeConfiguration(InetAddress host, int port) throws IOException {
58N/A Socket sock = new Socket(host, port);
58N/A XMLEncoder e = new XMLEncoder(sock.getOutputStream());
145N/A e.writeObject(threadConfig.get());
58N/A e.close();
58N/A try {
58N/A sock.close();
58N/A } catch (Exception ex) {
436N/A log.log(Level.INFO, "Couldn't close socket after writing configuration.", ex);
58N/A }
58N/A }
234N/A
471N/A protected void writeConfiguration() throws IOException {
471N/A writeConfiguration(configServerSocket.getInetAddress(), configServerSocket.getLocalPort());
471N/A }
471N/A
234N/A public void setConfiguration(Configuration configuration) {
234N/A this.configuration = configuration;
664N/A HistoryGuru.getInstance().invalidateRepositories(configuration.getRepositories());
235N/A register();
234N/A }
639N/A
639N/A public Configuration getConfiguration() {
639N/A return this.threadConfig.get();
639N/A }
58N/A
58N/A private ServerSocket configServerSocket;
58N/A
77N/A /**
77N/A * Try to stop the configuration listener thread
77N/A */
58N/A public void stopConfigurationListenerThread() {
58N/A try {
58N/A configServerSocket.close();
436N/A } catch (Exception e) { log.log(Level.FINE, "Stopping config listener thread: ", e); }
30N/A }
77N/A
77N/A /**
77N/A * Start a thread to listen on a socket to receive new configurations
77N/A * to use.
77N/A * @param endpoint The socket address to listen on
77N/A * @return true if the endpoint was available (and the thread was started)
77N/A */
58N/A public boolean startConfigurationListenerThread(SocketAddress endpoint) {
58N/A boolean ret = false;
58N/A
58N/A try {
58N/A configServerSocket = new ServerSocket();
58N/A configServerSocket.bind(endpoint);
58N/A ret = true;
58N/A final ServerSocket sock = configServerSocket;
58N/A Thread t = new Thread(new Runnable() {
58N/A public void run() {
58N/A while (!sock.isClosed()) {
471N/A Socket s = null;
58N/A try {
58N/A s = sock.accept();
471N/A log.info(" OpenGrok: Got request from " + s.getInetAddress().getHostAddress());
58N/A BufferedInputStream in = new BufferedInputStream(s.getInputStream());
58N/A
58N/A XMLDecoder d = new XMLDecoder(new BufferedInputStream(in));
58N/A Object obj = d.readObject();
58N/A d.close();
58N/A
58N/A if (obj instanceof Configuration) {
664N/A setConfiguration((Configuration)obj);
320N/A log.info("Configuration updated: " + configuration.getSourceRoot());
58N/A }
58N/A } catch (IOException e) {
688N/A log.log(Level.SEVERE, "Error reading config file: ",e);
688N/A } catch (RuntimeException e) {
688N/A log.log(Level.SEVERE, "Error parsing config file: ", e);
58N/A } finally {
471N/A if (s != null) {
471N/A try {
471N/A s.close();
471N/A } catch (IOException ex) {
471N/A log.log(Level.WARNING, "Interrupt closing config listener reader socket: ", ex);
471N/A }
471N/A }
58N/A }
58N/A }
58N/A }
58N/A });
58N/A t.start();
58N/A } catch (UnknownHostException ex) {
320N/A log.log(Level.FINE,"Problem resolving sender: ",ex);
58N/A } catch (IOException ex) {
320N/A log.log(Level.FINE,"I/O error when waiting for config: ",ex);
58N/A }
58N/A
58N/A if (!ret && configServerSocket != null) {
58N/A try {
58N/A configServerSocket.close();
58N/A } catch (IOException ex) {
320N/A log.log(Level.FINE,"I/O problem closing reader config socket: ",ex);
58N/A }
58N/A }
58N/A
58N/A return ret;
30N/A }
30N/A}