Home | History | Annotate | Download | only in configuration
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * See LICENSE.txt included in this distribution for the specific
      9  * language governing permissions and limitations under the License.
     10  *
     11  * When distributing Covered Code, include this CDDL HEADER in each
     12  * file and include the License file at LICENSE.txt.
     13  * If applicable, add the following below this CDDL HEADER, with the
     14  * fields enclosed by brackets "[]" replaced with your own identifying
     15  * information: Portions Copyright [yyyy] [name of copyright owner]
     16  *
     17  * CDDL HEADER END
     18  */
     19 
     20 /*
     21  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
     22  * Use is subject to license terms.
     23  */
     24 package org.opensolaris.opengrok.configuration;
     25 
     26 import java.beans.XMLDecoder;
     27 import java.beans.XMLEncoder;
     28 import java.io.BufferedInputStream;
     29 import java.io.File;
     30 import java.io.IOException;
     31 import java.net.InetAddress;
     32 import java.net.ServerSocket;
     33 import java.net.Socket;
     34 import java.net.SocketAddress;
     35 import java.net.UnknownHostException;
     36 import java.util.List;
     37 import java.util.Map;
     38 import java.util.logging.Level;
     39 import java.util.logging.Logger;
     40 import org.opensolaris.opengrok.OpenGrokLogger;
     41 import org.opensolaris.opengrok.history.Repository;
     42 import org.opensolaris.opengrok.index.IgnoredNames;
     43 import org.opensolaris.opengrok.util.Executor;
     44 
     45 /**
     46  * The RuntimeEnvironment class is used as a placeholder for the current
     47  * configuration this execution context (classloader) is using.
     48  */
     49 public final class RuntimeEnvironment {
     50     private Configuration configuration;
     51     private final ThreadLocal<Configuration> threadConfig;
     52 
     53     private static final Logger log = Logger.getLogger(RuntimeEnvironment.class.getName());
     54 
     55     private static RuntimeEnvironment instance = new RuntimeEnvironment();
     56 
     57     /**
     58      * Get the one and only instance of the RuntimeEnvironment
     59      * @return the one and only instance of the RuntimeEnvironment
     60      */
     61     public static RuntimeEnvironment getInstance() {
     62         return instance;
     63     }
     64 
     65     /**
     66      * Creates a new instance of RuntimeEnvironment. Private to ensure a
     67      * singleton pattern.
     68      */
     69     private RuntimeEnvironment() {
     70         configuration = new Configuration();
     71         threadConfig = new ThreadLocal<Configuration>() {
     72             @Override protected Configuration initialValue() {
     73                 return configuration;
     74             }
     75         };
     76     }
     77 
     78     private String getCanonicalPath(String s) {
     79         try {
     80             File file = new File(s);
     81             if (!file.exists()) {
     82                 return s;
     83             }
     84             return file.getCanonicalPath();
     85         } catch (IOException ex) {
     86             OpenGrokLogger.getLogger().log(Level.SEVERE, "Failed to get canonical path", ex);
     87             return s;
     88         }
     89     }
     90 
     91     /**
     92      * Get the path to the where the index database is stored
     93      * @return the path to the index database
     94      */
     95     public String getDataRootPath() {
     96         return threadConfig.get().getDataRoot();
     97     }
     98 
     99     /**
    100      * Get a file representing the index database
    101      * @return the index database
    102      */
    103     public File getDataRootFile() {
    104         File ret  = null;
    105         String file = getDataRootPath();
    106         if (file != null) {
    107             ret = new File(file);
    108         }
    109 
    110         return ret;
    111     }
    112 
    113     /**
    114      * Set the path to where the index database is stored
    115      * @param dataRoot the index database
    116      */
    117     public void setDataRoot(String dataRoot) {
    118         final File file = new File(dataRoot);
    119         if (!file.exists() && !file.mkdirs()) {
    120             OpenGrokLogger.getLogger().log(
    121                     Level.SEVERE, "Failed to create dataroot: " + dataRoot);
    122         }
    123         threadConfig.get().setDataRoot(getCanonicalPath(dataRoot));
    124     }
    125 
    126     /**
    127      * Get the path to where the sources are located
    128      * @return path to where the sources are located
    129      */
    130     public String getSourceRootPath() {
    131         return threadConfig.get().getSourceRoot();
    132     }
    133 
    134     /**
    135      * Get a file representing the directory where the sources are located
    136      * @return A file representing the directory where the sources are located
    137      */
    138     public File getSourceRootFile() {
    139         File ret  = null;
    140         String file = getSourceRootPath();
    141         if (file != null) {
    142             ret = new File(file);
    143         }
    144 
    145         return ret;
    146     }
    147 
    148     /**
    149      * Specify the source root
    150      * @param sourceRoot the location of the sources
    151      */
    152     public void setSourceRoot(String sourceRoot) {
    153         threadConfig.get().setSourceRoot(getCanonicalPath(sourceRoot));
    154     }
    155 
    156     /**
    157      * Do we have projects?
    158      * @return true if we have projects
    159      */
    160     public boolean hasProjects() {
    161         List<Project> proj = getProjects();
    162         return (proj != null && !proj.isEmpty());
    163     }
    164 
    165     /**
    166      * Get all of the projects
    167      * @return a list containing all of the projects (may be null)
    168      */
    169     public List<Project> getProjects() {
    170         return threadConfig.get().getProjects();
    171     }
    172 
    173     /**
    174      * Set the list of the projects
    175      * @param projects the list of projects to use
    176      */
    177     public void setProjects(List<Project> projects) {
    178         threadConfig.get().setProjects(projects);
    179     }
    180 
    181     /**
    182      * Register this thread in the thread/configuration map (so that all
    183      * subsequent calls to the RuntimeEnvironment from this thread will use
    184      * the same configuration
    185      */
    186     public void register() {
    187         threadConfig.set(configuration);
    188     }
    189 
    190     /**
    191      * Get the context name of the web application
    192      * @return the web applications context name
    193      */
    194     public String getUrlPrefix() {
    195         return threadConfig.get().getUrlPrefix();
    196     }
    197 
    198     /**
    199      * Set the web context name
    200      * @param urlPrefix the web applications context name
    201      */
    202     public void setUrlPrefix(String urlPrefix) {
    203         threadConfig.get().setUrlPrefix(urlPrefix);
    204     }
    205 
    206     /**
    207      * Get the name of the ctags program in use
    208      * @return the name of the ctags program in use
    209      */
    210     public String getCtags() {
    211         return threadConfig.get().getCtags();
    212     }
    213 
    214     /**
    215      * Specify the CTags program to use
    216      * @param ctags the ctags program to use
    217      */
    218     public void setCtags(String ctags) {
    219         threadConfig.get().setCtags(ctags);
    220     }
    221 
    222     /**
    223      * Validate that I have a Exuberant ctags program I may use
    224      * @return true if success, false otherwise
    225      */
    226     public boolean validateExuberantCtags() {
    227         boolean ret = true;
    228         Executor executor = new Executor(new String[] {getCtags(), "--version"});
    229 
    230         executor.exec(false);
    231         String output = executor.getOutputString();
    232         if (output == null || output.indexOf("Exuberant Ctags") == -1) {
    233             log.severe("Error: No Exuberant Ctags found in PATH!\n" +
    234                     "(tried running " + getCtags() + ")\n" +
    235                     "Please use option -c to specify path to a good Exuberant Ctags program");
    236             ret =  false;
    237         }
    238 
    239         return ret;
    240     }
    241 
    242     /**
    243      * Get the max time a SMC operation may use to avoid beeing cached
    244      * @return the max time
    245      */
    246     public int getHistoryReaderTimeLimit() {
    247         return threadConfig.get().getHistoryCacheTime();
    248     }
    249 
    250     /**
    251      * Specify the maximum time a SCM operation should take before it will
    252      * be cached (in ms)
    253      * @param historyReaderTimeLimit the max time in ms before it is cached
    254      */
    255     public void setHistoryReaderTimeLimit(int historyReaderTimeLimit) {
    256         threadConfig.get().setHistoryCacheTime(historyReaderTimeLimit);
    257     }
    258 
    259     /**
    260      * Is history cache currently enabled?
    261      * @return true if history cache is enabled
    262      */
    263     public boolean useHistoryCache() {
    264         return threadConfig.get().isHistoryCache();
    265     }
    266 
    267     /**
    268      * Specify if we should use history cache or not
    269      * @param useHistoryCache set false if you do not want to use history cache
    270      */
    271     public void setUseHistoryCache(boolean useHistoryCache) {
    272         threadConfig.get().setHistoryCache(useHistoryCache);
    273     }
    274 
    275     /**
    276      * Should we generate HTML or not during the indexing phase
    277      * @return true if HTML should be generated during the indexing phase
    278      */
    279     public boolean isGenerateHtml() {
    280         return threadConfig.get().isGenerateHtml();
    281     }
    282 
    283     /**
    284      * Specify if we should generate HTML or not during the indexing phase
    285      * @param generateHtml set this to true to pregenerate HTML
    286      */
    287     public void setGenerateHtml(boolean generateHtml) {
    288         threadConfig.get().setGenerateHtml(generateHtml);
    289     }
    290 
    291     /**
    292      * Set if we should compress the xref files or not
    293      * @param compressXref set to true if the generated html files should be
    294      *                     compressed
    295      */
    296     public void setCompressXref(boolean compressXref) {
    297         threadConfig.get().setCompressXref(compressXref);
    298     }
    299 
    300     /**
    301      * Are we using copressed HTML files?
    302      * @return true if the html-files should be compressed. false otherwise
    303      */
    304     public boolean isCompressXref() {
    305         return threadConfig.get().isCompressXref();
    306     }
    307 
    308     public boolean isQuickContextScan() {
    309         return threadConfig.get().isQuickContextScan();
    310     }
    311 
    312     public void setQuickContextScan(boolean quickContextScan) {
    313         threadConfig.get().setQuickContextScan(quickContextScan);
    314     }
    315 
    316     /**
    317      * Get the map of external SCM repositories available
    318      * @return A map containing all available SCMs
    319      */
    320     public Map<String, Repository> getRepositories() {
    321         return threadConfig.get().getRepositories();
    322     }
    323 
    324     /**
    325      * Set the map of external SCM repositories
    326      * @param repositories the repositories to use
    327      */
    328     public void setRepositories(Map<String, Repository> repositories) {
    329         threadConfig.get().setRepositories(repositories);
    330     }
    331 
    332     /**
    333      * Set the project that is specified to be the default project to use. The
    334      * default project is the project you will search (from the web application)
    335      * if the page request didn't contain the cookie..
    336      * @param defaultProject The default project to use
    337      */
    338     public void setDefaultProject(Project defaultProject) {
    339         threadConfig.get().setDefaultProject(defaultProject);
    340     }
    341 
    342     /**
    343      * Get the project that is specified to be the default project to use. The
    344      * default project is the project you will search (from the web application)
    345      * if the page request didn't contain the cookie..
    346      * @return the default project (may be null if not specified)
    347      */
    348     public Project getDefaultProject() {
    349         return threadConfig.get().getDefaultProject();
    350     }
    351 
    352     /**
    353      * Chandan wrote the following answer on the opengrok-discuss list:
    354      * "Traditionally search engines (specially spiders) think that large files
    355      * are junk. Large files tend to be multimedia files etc., which text
    356      * search spiders do not want to chew. So they ignore the contents of
    357      * the file after a cutoff length. Lucene does this by number of words,
    358      * which is by default is 10,000."
    359      * By default OpenGrok will increase this limit to 60000, but it may be
    360      * overridden in the configuration file
    361      * @return The maximum words to index
    362      */
    363     public int getIndexWordLimit() {
    364         return threadConfig.get().getIndexWordLimit();
    365     }
    366 
    367     /**
    368      * Set the number of words in a file Lucene will index.
    369      * See getIndexWordLimit for a better description.
    370      * @param indexWordLimit the number of words to index in a single file
    371      */
    372     public void setIndexWordLimit(int indexWordLimit) {
    373         threadConfig.get().setIndexWordLimit(indexWordLimit);
    374     }
    375 
    376     /**
    377      * Is the verbosity flag turned on?
    378      * @return true if we can print extra information
    379      */
    380     public boolean isVerbose() {
    381         return threadConfig.get().isVerbose();
    382     }
    383 
    384     /**
    385      * Set the verbosity flag (to add extra debug information in output)
    386      * @param verbose new value
    387      */
    388     public void setVerbose(boolean verbose) {
    389         threadConfig.get().setVerbose(verbose);
    390     }
    391 
    392     /**
    393      * Specify if a search may start with a wildcard. Note that queries
    394      * that start with a wildcard will give a significant impact on the
    395      * search performace.
    396      * @param allowLeadingWildcard set to true to activate (disabled by default)
    397      */
    398     public void setAllowLeadingWildcard(boolean allowLeadingWildcard) {
    399         threadConfig.get().setAllowLeadingWildcard(allowLeadingWildcard);
    400     }
    401 
    402     /**
    403      * Is leading wildcards allowed?
    404      * @return true if a search may start with a wildcard
    405      */
    406     public boolean isAllowLeadingWildcard() {
    407         return threadConfig.get().isAllowLeadingWildcard();
    408     }
    409 
    410     public IgnoredNames getIgnoredNames() {
    411         return threadConfig.get().getIgnoredNames();
    412     }
    413 
    414     public void setIgnoredNames(IgnoredNames ignoredNames) {
    415         threadConfig.get().setIgnoredNames(ignoredNames);
    416     }
    417 
    418     /**
    419      * Returns the user page for the history listing
    420      * @return the URL string fragment preceeding the username
    421      */
    422     public String getUserPage() {
    423         return threadConfig.get().getUserPage();
    424     }
    425 
    426     /**
    427      * Sets the user page for the history listing
    428      * @param userPage the URL fragment preceeding the username from history
    429      */
    430     public void setUserPage(String userPage) {
    431         threadConfig.get().setUserPage(userPage);
    432     }
    433 
    434     /**
    435      * Returns the bug page for the history listing
    436      * @return the URL string fragment preceeding the bug ID
    437      */
    438     public String getBugPage() {
    439         return threadConfig.get().getBugPage();
    440     }
    441 
    442     /**
    443      * Sets the bug page for the history listing
    444      * @param bugPage the URL fragment preceeding the bug ID
    445      */
    446     public void setBugPage(String bugPage) {
    447         threadConfig.get().setBugPage(bugPage);
    448     }
    449 
    450     /**
    451      * Returns the bug regex for the history listing
    452      * @return the regex that is looked for in history comments
    453      */
    454     public String getBugPattern() {
    455         return threadConfig.get().getBugPattern();
    456     }
    457 
    458     /**
    459      * Sets the bug regex for the history listing
    460      * @param bugPattern the regex to search history comments
    461      */
    462     public void setBugPattern(String bugPattern) {
    463         threadConfig.get().setBugPattern(bugPattern);
    464     }
    465 
    466 
    467     /**
    468      * Returns the review(ARC) page for the history listing
    469      * @return the URL string fragment preceeding the review page ID
    470      */
    471     public String getReviewPage() {
    472         return threadConfig.get().getReviewPage();
    473     }
    474 
    475      /**
    476      * Sets the review(ARC) page for the history listing
    477      * @param reviewPage the URL fragment preceeding the review page ID
    478      */
    479     public void setReviewPage(String reviewPage) {
    480         threadConfig.get().setReviewPage(reviewPage);
    481     }
    482 
    483     /**
    484      * Returns the review(ARC) regex for the history listing
    485      * @return the regex that is looked for in history comments
    486      */
    487     public String getReviewPattern() {
    488         return threadConfig.get().getReviewPattern();
    489     }
    490 
    491     /**
    492      * Sets the review(ARC) regex for the history listing
    493      * @param reviewPattern the regex to search history comments
    494      */
    495     public void setReviewPattern(String reviewPattern) {
    496         threadConfig.get().setReviewPattern(reviewPattern);
    497     }
    498 
    499     public String getWebappLAF() {
    500         return threadConfig.get().getWebappLAF();
    501     }
    502 
    503     public void setWebappLAF(String laf) {
    504         threadConfig.get().setWebappLAF(laf);
    505     }
    506 
    507     public boolean isRemoteScmSupported() {
    508         return threadConfig.get().isRemoteScmSupported();
    509     }
    510 
    511     public void setRemoteScmSupported(boolean supported) {
    512         threadConfig.get().setRemoteScmSupported(supported);
    513     }
    514 
    515     public boolean isOptimizeDatabase() {
    516         return threadConfig.get().isOptimizeDatabase();
    517     }
    518 
    519     public void setOptimizeDatabase(boolean optimizeDatabase) {
    520         threadConfig.get().setOptimizeDatabase(optimizeDatabase);
    521     }
    522 
    523     public boolean isUsingLuceneLocking() {
    524         return threadConfig.get().isUsingLuceneLocking();
    525     }
    526 
    527     public void setUsingLuceneLocking(boolean useLuceneLocking) {
    528         threadConfig.get().setUsingLuceneLocking(useLuceneLocking);
    529     }
    530 
    531     public boolean isIndexVersionedFilesOnly() {
    532         return threadConfig.get().isIndexVersionedFilesOnly();
    533     }
    534 
    535     public void setIndexVersionedFilesOnly(boolean indexVersionedFilesOnly) {
    536         threadConfig.get().setIndexVersionedFilesOnly(indexVersionedFilesOnly);
    537     }
    538 
    539     /**
    540      * Read an configuration file and set it as the current configuration.
    541      * @param file the file to read
    542      * @throws IOException if an error occurs
    543      */
    544     public void readConfiguration(File file) throws IOException {
    545         configuration = Configuration.read(file);
    546         register();
    547     }
    548 
    549     /**
    550      * Write the current configuration to a file
    551      * @param file the file to write the configuration into
    552      * @throws IOException if an error occurs
    553      */
    554     public void writeConfiguration(File file) throws IOException {
    555         threadConfig.get().write(file);
    556     }
    557 
    558     /**
    559      * Write the current configuration to a socket
    560      * @param host the host address to receive the configuration
    561      * @param port the port to use on the host
    562      * @throws IOException if an error occurs
    563      */
    564     public void writeConfiguration(InetAddress host, int port) throws IOException {
    565         Socket sock = new Socket(host, port);
    566         XMLEncoder e = new XMLEncoder(sock.getOutputStream());
    567         e.writeObject(threadConfig.get());
    568         e.close();
    569         try {
    570             sock.close();
    571         } catch (Exception ex) {
    572             log.log(Level.INFO, "Couldn't close socket after writing configuration.", ex);
    573         }
    574     }
    575 
    576     protected void writeConfiguration() throws IOException {
    577         writeConfiguration(configServerSocket.getInetAddress(), configServerSocket.getLocalPort());
    578     }
    579 
    580     public void setConfiguration(Configuration configuration) {
    581         this.configuration = configuration;
    582         register();
    583     }
    584 
    585     private ServerSocket configServerSocket;
    586 
    587     /**
    588      * Try to stop the configuration listener thread
    589      */
    590     public void stopConfigurationListenerThread() {
    591         try {
    592             configServerSocket.close();
    593         } catch (Exception e) { log.log(Level.FINE, "Stopping config listener thread: ", e); }
    594     }
    595 
    596     /**
    597      * Start a thread to listen on a socket to receive new configurations
    598      * to use.
    599      * @param endpoint The socket address to listen on
    600      * @return true if the endpoint was available (and the thread was started)
    601      */
    602     public boolean startConfigurationListenerThread(SocketAddress endpoint) {
    603         boolean ret = false;
    604 
    605         try {
    606             configServerSocket = new ServerSocket();
    607             configServerSocket.bind(endpoint);
    608             ret = true;
    609             final ServerSocket sock = configServerSocket;
    610             Thread t = new Thread(new Runnable() {
    611                 public void run() {
    612                     while (!sock.isClosed()) {
    613                         Socket s = null;
    614                         try {
    615                             s = sock.accept();
    616                             log.info(" OpenGrok: Got request from " + s.getInetAddress().getHostAddress());
    617                             BufferedInputStream in = new BufferedInputStream(s.getInputStream());
    618 
    619                             XMLDecoder d = new XMLDecoder(new BufferedInputStream(in));
    620                             Object obj = d.readObject();
    621                             d.close();
    622 
    623                             if (obj instanceof Configuration) {
    624                                 configuration = (Configuration)obj;
    625                                 log.info("Configuration updated: " + configuration.getSourceRoot());
    626                             }
    627                         } catch (IOException e) {
    628                             log.log(Level.WARNING, "Error reading config file: ",e);
    629                         } finally {
    630                             if (s != null) {
    631                                 try {
    632                                     s.close();
    633                                 } catch (IOException ex) {
    634                                     log.log(Level.WARNING, "Interrupt closing config listener reader socket: ", ex);
    635                                 }
    636                             }
    637                         }
    638                     }
    639                 }
    640             });
    641             t.start();
    642         } catch (UnknownHostException ex) {
    643             log.log(Level.FINE,"Problem resolving sender: ",ex);
    644         } catch (IOException ex) {
    645             log.log(Level.FINE,"I/O error when waiting for config: ",ex);
    646         }
    647 
    648         if (!ret && configServerSocket != null) {
    649             try {
    650                 configServerSocket.close();
    651             } catch (IOException ex) {
    652                 log.log(Level.FINE,"I/O problem closing reader config socket: ",ex);
    653             }
    654         }
    655 
    656         return ret;
    657     }
    658 }
    659