Configuration.java revision 1461
58N/A/*
58N/A * CDDL HEADER START
58N/A *
58N/A * The contents of this file are subject to the terms of the
58N/A * Common Development and Distribution License (the "License").
58N/A * You may not use this file except in compliance with the License.
58N/A *
58N/A * See LICENSE.txt included in this distribution for the specific
58N/A * language governing permissions and limitations under the License.
58N/A *
58N/A * When distributing Covered Code, include this CDDL HEADER in each
58N/A * file and include the License file at LICENSE.txt.
58N/A * If applicable, add the following below this CDDL HEADER, with the
58N/A * fields enclosed by brackets "[]" replaced with your own identifying
58N/A * information: Portions Copyright [yyyy] [name of copyright owner]
58N/A *
58N/A * CDDL HEADER END
58N/A */
58N/A
58N/A/*
1291N/A * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
1356N/A * Portions Copyright 2011, 2012 Jens Elkner.
58N/A */
58N/Apackage org.opensolaris.opengrok.configuration;
58N/A
234N/Aimport java.beans.XMLDecoder;
234N/Aimport java.beans.XMLEncoder;
234N/Aimport java.io.BufferedInputStream;
234N/Aimport java.io.BufferedOutputStream;
1287N/Aimport java.io.BufferedReader;
639N/Aimport java.io.ByteArrayInputStream;
639N/Aimport java.io.ByteArrayOutputStream;
234N/Aimport java.io.File;
234N/Aimport java.io.FileInputStream;
234N/Aimport java.io.FileOutputStream;
1289N/Aimport java.io.FileReader;
234N/Aimport java.io.IOException;
639N/Aimport java.io.InputStream;
639N/Aimport java.io.OutputStream;
58N/Aimport java.util.ArrayList;
1185N/Aimport java.util.Collections;
667N/Aimport java.util.Date;
1185N/Aimport java.util.HashMap;
1016N/Aimport java.util.HashSet;
58N/Aimport java.util.List;
1185N/Aimport java.util.Map;
1016N/Aimport java.util.Set;
1436N/Aimport java.util.logging.Logger;
1185N/A
664N/Aimport org.opensolaris.opengrok.history.RepositoryInfo;
1026N/Aimport org.opensolaris.opengrok.index.Filter;
112N/Aimport org.opensolaris.opengrok.index.IgnoredNames;
1195N/Aimport org.opensolaris.opengrok.util.IOUtils;
1419N/Aimport org.opensolaris.opengrok.web.Prefix;
58N/A
58N/A/**
77N/A * Placeholder class for all configuration variables. Due to the multithreaded
77N/A * nature of the web application, each thread will use the same instance of the
77N/A * configuration object for each page request. Class and methods should have
77N/A * package scope, but that didn't work with the XMLDecoder/XMLEncoder.
58N/A */
418N/Apublic final class Configuration {
1436N/A
1327N/A /** The property name used to obtain the ctags command to use. */
1327N/A public static final String CTAGS_CMD_PROPERTY_KEY =
1327N/A "org.opensolaris.opengrok.analysis.Ctags";
1327N/A /** The command to use if no ctags command was given explicitly */
1327N/A public static final String CTAGS_CMD_FALLBACK = "ctags";
1327N/A
1356N/A /** Relative path wrt. servlet context to the default CSS to use */
1356N/A public static final String DEFAULT_STYLE = "static/default";
1356N/A
58N/A private String ctags;
1436N/A /**
1436N/A * Should the history log be cached?
1436N/A */
58N/A private boolean historyCache;
773N/A /**
773N/A * The maximum time in milliseconds {@code HistoryCache.get()} can take
773N/A * before its result is cached.
773N/A */
58N/A private int historyCacheTime;
1436N/A /**
1436N/A * Should the history cache be stored in a database?
1436N/A */
773N/A private boolean historyCacheInDB;
773N/A
58N/A private List<Project> projects;
58N/A private String sourceRoot;
58N/A private String dataRoot;
664N/A private List<RepositoryInfo> repositories;
58N/A private String urlPrefix;
65N/A private boolean generateHtml;
1436N/A /**
1436N/A * Default project will be used, when no project is selected and no project
1436N/A * is in cookie, so basically only the first time you open the first page,
1436N/A * or when you clear your web cookies
1436N/A */
77N/A private Project defaultProject;
99N/A private int indexWordLimit;
99N/A private boolean verbose;
1115N/A //if below is set, then we count how many files per project we need to process and print percentage of completion per project
1115N/A private boolean printProgress;
125N/A private boolean allowLeadingWildcard;
112N/A private IgnoredNames ignoredNames;
1026N/A private Filter includedNames;
129N/A private String userPage;
1100N/A private String userPageSuffix;
129N/A private String bugPage;
129N/A private String bugPattern;
318N/A private String reviewPage;
318N/A private String reviewPattern;
144N/A private String webappLAF;
173N/A private boolean remoteScmSupported;
253N/A private boolean optimizeDatabase;
296N/A private boolean useLuceneLocking;
335N/A private boolean compressXref;
480N/A private boolean indexVersionedFilesOnly;
816N/A private int hitsPerPage;
816N/A private int cachePages;
833N/A private String databaseDriver;
833N/A private String databaseUrl;
1416N/A private String ctagsOptionsFile;
1185N/A private int scanningDepth;
1016N/A private Set<String> allowedSymlinks;
1123N/A private boolean obfuscatingEMailAddresses;
1125N/A private boolean chattyStatusPage;
1218N/A private final Map<String,String> cmds;
1185N/A private int tabSize;
1326N/A private static final Logger logger = Logger.getLogger(Configuration.class.getName());
993N/A
1185N/A /**
1185N/A * Get the default tab size (number of space characters per tab character)
1190N/A * to use for each project. If {@code <= 0} tabs are read/write as is.
1436N/A *
1185N/A * @return current tab size set.
1185N/A * @see Project#getTabSize()
1252N/A * @see org.opensolaris.opengrok.analysis.ExpandTabsReader
1185N/A */
1185N/A public int getTabSize() {
1185N/A return tabSize;
1185N/A }
1185N/A
1185N/A /**
1185N/A * Set the default tab size (number of space characters per tab character)
1185N/A * to use for each project. If {@code <= 0} tabs are read/write as is.
1436N/A *
1185N/A * @param tabSize tabsize to set.
1185N/A * @see Project#setTabSize(int)
1252N/A * @see org.opensolaris.opengrok.analysis.ExpandTabsReader
1185N/A */
1185N/A public void setTabSize(int tabSize) {
1185N/A this.tabSize = tabSize;
1185N/A }
1185N/A
1461N/A /**
1461N/A * Get the depth of scanning for repositories in the directory tree relative
1461N/A * to source root.
1461N/A * @return the scan depth.
1461N/A */
1185N/A public int getScanningDepth() {
993N/A return scanningDepth;
993N/A }
993N/A
1461N/A /**
1461N/A * Set the depth of scanning for repositories in the directory tree relative
1461N/A * to source root.
1461N/A * @param scanningDepth the scan depth to set.
1461N/A */
1185N/A public void setScanningDepth(int scanningDepth) {
993N/A this.scanningDepth = scanningDepth;
993N/A }
937N/A
1436N/A /**
1436N/A * Creates a new instance of Configuration
1436N/A */
58N/A public Configuration() {
816N/A //defaults for an opengrok instance configuration
58N/A setHistoryCache(true);
58N/A setHistoryCacheTime(30);
773N/A setHistoryCacheInDB(false);
58N/A setProjects(new ArrayList<Project>());
664N/A setRepositories(new ArrayList<RepositoryInfo>());
1419N/A setUrlPrefix("/source" + Prefix.SEARCH_R + '?');
1419N/A // TODO generate relative search paths, get rid of -w <webapp> option to indexer !
1419N/A // setUrlPrefix(".." + Prefix.SEARCH_R + '?');
1327N/A setCtags(System.getProperty(CTAGS_CMD_PROPERTY_KEY, CTAGS_CMD_FALLBACK));
870N/A //below can cause an outofmemory error, since it is defaulting to NO LIMIT
870N/A setIndexWordLimit(Integer.MAX_VALUE);
99N/A setVerbose(false);
1115N/A setPrintProgress(false);
101N/A setGenerateHtml(true);
106N/A setQuickContextScan(true);
112N/A setIgnoredNames(new IgnoredNames());
1026N/A setIncludedNames(new Filter());
129N/A setUserPage("http://www.opensolaris.org/viewProfile.jspa?username=");
129N/A setBugPage("http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=");
129N/A setBugPattern("\\b([12456789][0-9]{6})\\b");
875N/A setReviewPage("http://arc.opensolaris.org/caselog/PSARC/");
318N/A setReviewPattern("\\b(\\d{4}/\\d{3})\\b"); // in form e.g. PSARC 2008/305
1356N/A setWebappLAF(DEFAULT_STYLE);
173N/A setRemoteScmSupported(false);
253N/A setOptimizeDatabase(true);
296N/A setUsingLuceneLocking(false);
335N/A setCompressXref(true);
480N/A setIndexVersionedFilesOnly(false);
816N/A setHitsPerPage(25);
816N/A setCachePages(5);
993N/A setScanningDepth(3); // default depth of scanning for repositories
1016N/A setAllowedSymlinks(new HashSet<String>());
1315N/A //setTabSize(4);
1185N/A cmds = new HashMap<String, String>();
58N/A }
937N/A
1461N/A /**
1461N/A * Get the client command to use to access the repository for the given
1461N/A * fully quallified classname.
1461N/A * @param clazzName name of the targeting class
1461N/A * @return {@code null} if not yet set, the client command otherwise.
1461N/A */
1185N/A public String getRepoCmd(String clazzName) {
1185N/A return cmds.get(clazzName);
1185N/A }
1190N/A
1461N/A /**
1461N/A * Set the client command to use to access the repository for the given
1461N/A * fully quallified classname.
1461N/A * @param clazzName name of the targeting class. If {@code null} this method
1461N/A * does nothing.
1461N/A * @param cmd the client command to use. If {@code null} the corresponding
1461N/A * entry for the given clazzName get removed.
1461N/A * @return the client command previously set, which might be {@code null}.
1461N/A */
1185N/A public String setRepoCmd(String clazzName, String cmd) {
1185N/A if (clazzName == null) {
1185N/A return null;
1185N/A }
1185N/A if (cmd == null || cmd.length() == 0) {
1185N/A return cmds.remove(clazzName);
1185N/A }
1185N/A return cmds.put(clazzName, cmd);
1185N/A }
1185N/A
1461N/A /**
1461N/A * Get a map of repository class names with the corresponding CLI command to
1461N/A * access the repository it is able to handle.
1461N/A * Basically exists to satisfy bean/de|encoder stuff, only.
1461N/A * @return a unmodifyable map.
1461N/A */
1185N/A public Map<String, String> getCmds() {
1185N/A return Collections.unmodifiableMap(cmds);
1185N/A }
1190N/A
1461N/A /**
1461N/A * Set the map of repository class names with the corresponding CLI command
1461N/A * to access the repository it is able to handle.
1461N/A * Basically exists to satisfy bean/de|encoder stuff, only.
1461N/A * @param cmds the map to copy.
1461N/A */
1185N/A public void setCmds(Map<String, String> cmds) {
1185N/A this.cmds.clear();
1185N/A this.cmds.putAll(cmds);
1185N/A }
1190N/A
1461N/A /**
1461N/A * Get the name of the ctags program in use
1461N/A * @return the name of the ctags program in use
1461N/A */
58N/A public String getCtags() {
58N/A return ctags;
58N/A }
937N/A
1461N/A /**
1461N/A * Specify the CTags program to use
1461N/A * @param ctags the ctags program to use
1461N/A */
58N/A public void setCtags(String ctags) {
58N/A this.ctags = ctags;
58N/A }
937N/A
1461N/A /**
1461N/A * Get the number of search result pages, which should be cached in
1461N/A * a search result.
1461N/A * @return the number of result pages to cache.
1461N/A * @see #getHitsPerPage()
1461N/A */
816N/A public int getCachePages() {
816N/A return cachePages;
816N/A }
816N/A
1461N/A /**
1461N/A * Set the number of search result pages, which should be cached in
1461N/A * a search result.
1461N/A * @param cachePages the number of result pages to cache.
1461N/A * @see #getHitsPerPage()
1461N/A */
816N/A public void setCachePages(int cachePages) {
816N/A this.cachePages = cachePages;
816N/A }
816N/A
1461N/A /**
1461N/A * Get the number of hits to display on one search result page.
1461N/A * @return number of hits per page.
1461N/A */
816N/A public int getHitsPerPage() {
816N/A return hitsPerPage;
816N/A }
816N/A
1461N/A /**
1461N/A * Set the number of hits to display on one search result page.
1461N/A * @param hitsPerPage number of hits per page to set.
1461N/A */
816N/A public void setHitsPerPage(int hitsPerPage) {
816N/A this.hitsPerPage = hitsPerPage;
816N/A }
773N/A
773N/A /**
773N/A * Should the history log be cached?
1436N/A *
1436N/A * @return {@code true} if a {@code HistoryCache} implementation should be
1436N/A * used, {@code false} otherwise
773N/A */
58N/A public boolean isHistoryCache() {
58N/A return historyCache;
58N/A }
773N/A
773N/A /**
773N/A * Set whether history should be cached.
1436N/A *
773N/A * @param historyCache if {@code true} enable history cache
773N/A */
58N/A public void setHistoryCache(boolean historyCache) {
58N/A this.historyCache = historyCache;
58N/A }
773N/A
773N/A /**
1436N/A * How long can a history request take before it's cached? If the time is
1436N/A * exceeded, the result is cached. This setting only affects
773N/A * {@code FileHistoryCache}.
773N/A *
773N/A * @return the maximum time in milliseconds a history request can take
773N/A * before it's cached
773N/A */
58N/A public int getHistoryCacheTime() {
58N/A return historyCacheTime;
58N/A }
773N/A
773N/A /**
1436N/A * Set the maximum time a history request can take before it's cached. This
1436N/A * setting is only respected if {@code FileHistoryCache} is used.
773N/A *
773N/A * @param historyCacheTime maximum time in milliseconds
773N/A */
58N/A public void setHistoryCacheTime(int historyCacheTime) {
58N/A this.historyCacheTime = historyCacheTime;
58N/A }
773N/A
773N/A /**
773N/A * Should the history cache be stored in a database? If yes,
773N/A * {@code JDBCHistoryCache} will be used to cache the history; otherwise,
773N/A * {@code FileHistoryCache} is used.
773N/A *
773N/A * @return whether the history cache should be stored in a database
773N/A */
773N/A public boolean isHistoryCacheInDB() {
773N/A return historyCacheInDB;
773N/A }
773N/A
773N/A /**
773N/A * Set whether the history cache should be stored in a database, and
773N/A * {@code JDBCHistoryCache} should be used instead of {@code
773N/A * FileHistoryCache}.
773N/A *
1436N/A * @param historyCacheInDB whether the history cached should be stored in a
1436N/A * database
773N/A */
773N/A public void setHistoryCacheInDB(boolean historyCacheInDB) {
773N/A this.historyCacheInDB = historyCacheInDB;
773N/A }
937N/A
1461N/A /**
1461N/A * Get all of the projects
1461N/A * @return a list containing all of the projects (may be null)
1461N/A */
58N/A public List<Project> getProjects() {
58N/A return projects;
58N/A }
937N/A
1461N/A /**
1461N/A * Set the list of the projects
1461N/A * @param projects the list of projects to use
1461N/A */
58N/A public void setProjects(List<Project> projects) {
58N/A this.projects = projects;
58N/A }
937N/A
1461N/A /**
1461N/A * Get the path to where the sources are located
1461N/A * @return path to where the sources are located
1461N/A */
58N/A public String getSourceRoot() {
58N/A return sourceRoot;
58N/A }
937N/A
1461N/A /**
1461N/A * Specify the source root
1461N/A * @param sourceRoot the location of the sources
1461N/A */
58N/A public void setSourceRoot(String sourceRoot) {
58N/A this.sourceRoot = sourceRoot;
58N/A }
937N/A
1461N/A /**
1461N/A * Get the path to the where the index database is stored
1461N/A * @return the path to the index database
1461N/A */
58N/A public String getDataRoot() {
58N/A return dataRoot;
58N/A }
937N/A
1461N/A /**
1461N/A * Set the path to where the index database is stored
1461N/A * @param dataRoot the index database
1461N/A */
58N/A public void setDataRoot(String dataRoot) {
58N/A this.dataRoot = dataRoot;
58N/A }
937N/A
1461N/A /**
1461N/A * Get the map of known repositories.
1461N/A * @return a possible empty list including {@code null}.
1461N/A */
664N/A public List<RepositoryInfo> getRepositories() {
58N/A return repositories;
58N/A }
937N/A
1461N/A /**
1461N/A * Set the map of known repositories.
1461N/A * @param repositories the repositories to set.
1461N/A */
664N/A public void setRepositories(List<RepositoryInfo> repositories) {
58N/A this.repositories = repositories;
58N/A }
937N/A
1461N/A /**
1461N/A * Get the context name of the web application.
1461N/A * @return the web applications context name.
1461N/A */
58N/A public String getUrlPrefix() {
58N/A return urlPrefix;
58N/A }
937N/A
1185N/A /**
1252N/A * Set the URL prefix to be used by the {@link
1252N/A * org.opensolaris.opengrok.analysis.executables.JavaClassAnalyzer} as well
1436N/A * as lexers (see {@link org.opensolaris.opengrok.analysis.JFlexXref}) when
1436N/A * they create output with html links.
1436N/A *
1185N/A * @param urlPrefix prefix to use.
1185N/A */
58N/A public void setUrlPrefix(String urlPrefix) {
58N/A this.urlPrefix = urlPrefix;
58N/A }
937N/A
1461N/A /**
1461N/A * Set whether to generate hyper text cross reference (xref) files
1461N/A * offline (i.e. when indexing). If set to {@code false}, xref files are
1461N/A * created on the fly on demand and gets disposed when served to the client
1461N/A * - so saves disk space, but could be sightly slow and more resource
1461N/A * demanding for the servlet container.
1461N/A * @param generateHtml {@code true} to generate and cache xref files immediately.
1461N/A */
65N/A public void setGenerateHtml(boolean generateHtml) {
65N/A this.generateHtml = generateHtml;
65N/A }
937N/A
1461N/A /**
1461N/A * Check, whether to generate and cache xref files immediately.
1461N/A * @return {@code true} if immediate generation/caching is preferred.
1461N/A */
65N/A public boolean isGenerateHtml() {
65N/A return generateHtml;
65N/A }
937N/A
1461N/A /**
1461N/A * Set the project that is specified to be the default project to use. The
1461N/A * default project is the project you will search (from the web application)
1461N/A * if the page request didn't contain the cookie.
1461N/A * @param defaultProject The default project to use
1461N/A */
77N/A public void setDefaultProject(Project defaultProject) {
77N/A this.defaultProject = defaultProject;
77N/A }
937N/A
1461N/A /**
1461N/A * Get the project that is specified to be the default project to use. The
1461N/A * default project is the project you will search (from the web application)
1461N/A * if the page request didn't contain the cookie.
1461N/A * @return the default project (may be null if not specified)
1461N/A */
77N/A public Project getDefaultProject() {
77N/A return defaultProject;
77N/A }
99N/A
1461N/A /**
1461N/A * Chandan wrote the following answer on the opengrok-discuss list:
1461N/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
1461N/A * the file after a cutoff length. Lucene does this by number of words,
1461N/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
1461N/A */
99N/A public int getIndexWordLimit() {
99N/A return indexWordLimit;
99N/A }
99N/A
1461N/A /**
1461N/A * Set the number of words in a file Lucene will index.
1461N/A * See getIndexWordLimit for a better description.
1461N/A * @param indexWordLimit the number of words to index in a single file
1461N/A */
99N/A public void setIndexWordLimit(int indexWordLimit) {
99N/A this.indexWordLimit = indexWordLimit;
99N/A }
99N/A
1461N/A /**
1461N/A * Is the verbosity flag turned on?
1461N/A * @return true if we can print extra information
1461N/A */
99N/A public boolean isVerbose() {
99N/A return verbose;
99N/A }
99N/A
1461N/A /**
1461N/A * Set the verbosity flag (to add extra debug information in output)
1461N/A * @param verbose new value
1461N/A */
99N/A public void setVerbose(boolean verbose) {
99N/A this.verbose = verbose;
99N/A }
937N/A
1461N/A /**
1461N/A * Is the progress print flag turned on?
1461N/A * @return {@code true} if we can print per project progress %
1461N/A */
1115N/A public boolean isPrintProgress() {
1115N/A return printProgress;
1115N/A }
1115N/A
1461N/A /**
1461N/A * Set the printing of progress % flag (user convenience).
1461N/A * @param enable {@code true} to enable progress printing.
1461N/A */
1461N/A public void setPrintProgress(boolean enable) {
1461N/A this.printProgress = enable;
1115N/A }
1115N/A
1461N/A /**
1461N/A * Specify if a search may start with a wildcard. Note that queries
1461N/A * that start with a wildcard will give a significant impact on the
1461N/A * search performace (disabled by default).
1461N/A * @param allowLeadingWildcard set to {@code true} to activate
1461N/A */
125N/A public void setAllowLeadingWildcard(boolean allowLeadingWildcard) {
125N/A this.allowLeadingWildcard = allowLeadingWildcard;
125N/A }
937N/A
1461N/A /**
1461N/A * Is leading wildcards allowed?
1461N/A * @return {@code true} if a search may start with a wildcard
1461N/A */
125N/A public boolean isAllowLeadingWildcard() {
125N/A return allowLeadingWildcard;
125N/A }
106N/A
106N/A private boolean quickContextScan;
937N/A
1461N/A /**
1461N/A * Check whether a quick context scan should be done.
1461N/A * @return {@code true} if quick scan should be made.
1461N/A * @see #setQuickContextScan(boolean)
1461N/A */
106N/A public boolean isQuickContextScan() {
106N/A return quickContextScan;
106N/A }
937N/A
1461N/A /**
1461N/A * If set to {@code true}, at most 1 MiB of a file gets read into a buffer
1461N/A * at once and than tokenized. Otherwise the whole file gets processed as
1461N/A * usual, i.e. the file content gets read on demand when tokenizing and the
1461N/A * whole file gets processed (no matter of its size).
1461N/A * @param quickContextScan if {@code true} enable quick scanning
1461N/A */
106N/A public void setQuickContextScan(boolean quickContextScan) {
106N/A this.quickContextScan = quickContextScan;
106N/A }
112N/A
1461N/A /**
1461N/A * Set the list of names/patterns to determine file, which should be
1461N/A * ignored/excluded from indexing.
1461N/A * Takes precedence over {@link #getIncludedNames()}.
1461N/A * @param ignoredNames stuff to ignore. If {@code null} defaults will be
1461N/A * used instead.
1461N/A */
112N/A public void setIgnoredNames(IgnoredNames ignoredNames) {
1461N/A this.ignoredNames = ignoredNames == null ? new IgnoredNames() : ignoredNames;
112N/A }
112N/A
1461N/A /**
1461N/A * Get the list of names/patterns to determine file, which should be
1461N/A * ignored/excluded from indexing.
1461N/A * Takes precedence over {@link #getIncludedNames()}.
1461N/A * @return stuff to ignore.
1461N/A */
112N/A public IgnoredNames getIgnoredNames() {
112N/A return ignoredNames;
112N/A }
129N/A
1461N/A /**
1461N/A * Set the list of names/patterns to determine, which are allowed to
1461N/A * be indexed.
1461N/A * @param includedNames stuff to index. {@code null} means everything.
1461N/A * @see #setIgnoredNames(IgnoredNames)
1461N/A */
1026N/A public void setIncludedNames(Filter includedNames) {
1026N/A this.includedNames = includedNames;
1026N/A }
1026N/A
1461N/A /**
1461N/A * Get the list of names/patterns to determine, which are allowed to
1461N/A * be indexed.
1461N/A * @return stuff to index. {@code null} means everything.
1461N/A * @see #getIgnoredNames()
1461N/A */
1026N/A public Filter getIncludedNames() {
1026N/A return includedNames;
1026N/A }
1026N/A
1461N/A /**
1461N/A * Sets the user page for the history listing
1461N/A * @param userPage the URL fragment preceeding the username from history
1461N/A */
129N/A public void setUserPage(String userPage) {
129N/A this.userPage = userPage;
129N/A }
129N/A
1461N/A /**
1461N/A * Returns the user page for the history listing
1461N/A * @return the URL string fragment preceeding the username
1461N/A */
129N/A public String getUserPage() {
129N/A return userPage;
129N/A }
129N/A
1461N/A /**
1461N/A * Sets the user page suffix for the history listing
1461N/A * @param userPageSuffix the URL fragment following the username from history
1461N/A */
1100N/A public void setUserPageSuffix(String userPageSuffix) {
1100N/A this.userPageSuffix = userPageSuffix;
1100N/A }
1100N/A
1461N/A /**
1461N/A * Returns the user page suffix for the history listing
1461N/A * @return the URL string fragment following the username
1461N/A */
1100N/A public String getUserPageSuffix() {
1100N/A return userPageSuffix;
1100N/A }
1100N/A
1461N/A /**
1461N/A * Sets the bug page for the history listing
1461N/A * @param bugPage the URL fragment preceeding the bug ID
1461N/A */
129N/A public void setBugPage(String bugPage) {
129N/A this.bugPage = bugPage;
129N/A }
129N/A
1461N/A /**
1461N/A * Returns the bug page for the history listing
1461N/A * @return the URL string fragment preceeding the bug ID
1461N/A */
129N/A public String getBugPage() {
129N/A return bugPage;
129N/A }
129N/A
1461N/A /**
1461N/A * Sets the bug regex for the history listing
1461N/A * @param bugPattern the regex to search history comments
1461N/A */
129N/A public void setBugPattern(String bugPattern) {
129N/A this.bugPattern = bugPattern;
129N/A }
129N/A
1461N/A /**
1461N/A * Returns the bug regex for the history listing
1461N/A * @return the regex that is looked for in history comments
1461N/A */
129N/A public String getBugPattern() {
129N/A return bugPattern;
129N/A }
937N/A
1461N/A /**
1461N/A * Returns the review(ARC) page for the history listing
1461N/A * @return the URL string fragment preceeding the review page ID
1461N/A */
318N/A public String getReviewPage() {
318N/A return reviewPage;
318N/A }
318N/A
1461N/A /**
1461N/A * Sets the review(ARC) page for the history listing
1461N/A * @param reviewPage the URL fragment preceeding the review page ID
1461N/A */
318N/A public void setReviewPage(String reviewPage) {
318N/A this.reviewPage = reviewPage;
318N/A }
318N/A
1461N/A /**
1461N/A * Returns the review(ARC) regex for the history listing
1461N/A * @return the regex that is looked for in history comments
1461N/A */
318N/A public String getReviewPattern() {
318N/A return reviewPattern;
318N/A }
318N/A
1461N/A /**
1461N/A * Sets the review(ARC) regex for the history listing
1461N/A * @param reviewPattern the regex to search history comments
1461N/A */
318N/A public void setReviewPattern(String reviewPattern) {
318N/A this.reviewPattern = reviewPattern;
318N/A }
144N/A
1461N/A /**
1461N/A * Get the name of the web app Look And Feel (LAF) theme to use. It gets
1461N/A * used to construct the stylesheet and image include links in web pages
1461N/A * and names a directory, which contains all this stuff.
1461N/A * @return the name of the web app LAF
1461N/A * @see #DEFAULT_STYLE
1461N/A */
144N/A public String getWebappLAF() {
144N/A return webappLAF;
144N/A }
144N/A
1461N/A /**
1461N/A * Set the name of the web app Look And Feel (LAF) theme to use. It gets
1461N/A * used to construct the stylesheet and image include links in web pages
1461N/A * and names a directory, which contains all this stuff.
1461N/A * @param webappLAF the name of the web app LAF. If {@code null} the default
1461N/A * will be used.
1461N/A * @see #DEFAULT_STYLE
1461N/A */
144N/A public void setWebappLAF(String webappLAF) {
1461N/A this.webappLAF = webappLAF == null ? DEFAULT_STYLE : webappLAF;
144N/A }
173N/A
1461N/A /**
1461N/A * Check whether file histories should be retrieved from the related remote
1461N/A * repositories when needed.
1461N/A * @return {@code true} if fetch on demand is enabled.
1461N/A */
173N/A public boolean isRemoteScmSupported() {
173N/A return remoteScmSupported;
173N/A }
173N/A
1461N/A /**
1461N/A * Set whether file histories should be retrieved from the related remote
1461N/A * repositories when needed.
1461N/A * @param remoteScmSupported {@code true} if fetch on demand is enabled.
1461N/A */
173N/A public void setRemoteScmSupported(boolean remoteScmSupported) {
173N/A this.remoteScmSupported = remoteScmSupported;
173N/A }
234N/A
1461N/A /**
1461N/A * Check, whether the lucene index database should be optimized (compact
1461N/A * segments etc.) after indexing has been run.
1461N/A * @return {@code true} if optimization is enabled.
1461N/A */
253N/A public boolean isOptimizeDatabase() {
253N/A return optimizeDatabase;
253N/A }
253N/A
1461N/A /**
1461N/A * Set, whether the lucene index database should be optimized (compact
1461N/A * segments etc.) after indexing has been run.
1461N/A * @param optimizeDatabase {@code true} if optimization should be done.
1461N/A */
253N/A public void setOptimizeDatabase(boolean optimizeDatabase) {
253N/A this.optimizeDatabase = optimizeDatabase;
253N/A }
253N/A
1461N/A /**
1461N/A * Check, wheter lucene should lock index files when indexing to avoid
1461N/A * concurrent access, reading invalid data.
1461N/A * @return {@code true} if locking should be used.
1461N/A */
296N/A public boolean isUsingLuceneLocking() {
296N/A return useLuceneLocking;
296N/A }
296N/A
1461N/A /**
1461N/A * Set wheter lucene should lock index files when indexing to avoid
1461N/A * concurrent access, reading invalid data.
1461N/A * @param useLuceneLocking {@code true} if locking should be used.
1461N/A */
296N/A public void setUsingLuceneLocking(boolean useLuceneLocking) {
296N/A this.useLuceneLocking = useLuceneLocking;
296N/A }
335N/A
1461N/A /**
1461N/A * Set if we should compress the xref files or not. Applies to newly
1461N/A * generated/updated files, only. Re-indexing is not needed, since the
1461N/A * application automatically detects, whether an xref file is compressed
1461N/A * and processes it properly.
1461N/A * @param compressXref set to {@code true} if generated xref html files
1461N/A * should be compressed
1461N/A */
335N/A public void setCompressXref(boolean compressXref) {
335N/A this.compressXref = compressXref;
335N/A }
335N/A
1461N/A /**
1461N/A * Set if we should compress generated xref html files?
1461N/A * @return {@code true} if the xref html files should be compressed.
1461N/A */
335N/A public boolean isCompressXref() {
335N/A return compressXref;
335N/A }
335N/A
1461N/A /**
1461N/A * Check, whether unversioned files should not be indexed.
1461N/A * If {@code true}, it takes precedence over {@link #getIncludedNames()},
1461N/A * i.e. files are not indexed when unversioned, even if they match an
1461N/A * include name.
1461N/A * @return {@code true} if indexing of unversioned files is disabled.
1461N/A */
480N/A public boolean isIndexVersionedFilesOnly() {
480N/A return indexVersionedFilesOnly;
480N/A }
480N/A
1461N/A /**
1461N/A * Set, whether unversioned files should not be indexed.
1461N/A * If set to {@code true}, it takes precedence over {@link #getIncludedNames()},
1461N/A * i.e. files are not indexed when unversioned, even if they match an
1461N/A * include name.
1461N/A * @param indexVersionedFilesOnly {@code true} to disable indexing of
1461N/A * unversioned files
1461N/A */
480N/A public void setIndexVersionedFilesOnly(boolean indexVersionedFilesOnly) {
480N/A this.indexVersionedFilesOnly = indexVersionedFilesOnly;
480N/A }
937N/A
1330N/A private transient long lastModified;
1330N/A /**
1330N/A * Get the time, when this instance has been modified. If not explicitly set
1330N/A * or set to {@code 0}, it gets initialized with the time of the first call
1330N/A * to this method after instantiation/de-serialization.
1330N/A *
1330N/A * @return time in milliseconds since 1 Jan 1970 00:00:00 GMT
1330N/A */
1330N/A public long getLastModified() {
1330N/A if (lastModified == 0) {
1330N/A // since we use it for If-Last-Modified-Since evals, which has no
1330N/A // millis, we need to clear the milliseconds part
1330N/A lastModified = System.currentTimeMillis()/1000 * 1000;
1330N/A }
1330N/A return lastModified;
1330N/A }
1330N/A /**
1330N/A * Set the time, when this configuration has been modified for the last time.
1330N/A * @param lastModified the time in milliseconds since 1 Jan 1970 00:00:00 GMT
1330N/A */
1330N/A public void setLastModified(long lastModified) {
1330N/A this.lastModified = lastModified/1000 * 1000;
1330N/A }
1330N/A
1330N/A private transient Date indexLastModified;
1324N/A /**
1324N/A * Get the date of the last index update.
1436N/A *
1324N/A * @return the time of the last index update.
1324N/A */
937N/A public Date getDateForLastIndexRun() {
1461N/A if (indexLastModified == null) {
1436N/A File timestamp = new File(getDataRoot(), "timestamp");
1461N/A indexLastModified = new Date(timestamp.lastModified());
1435N/A }
1461N/A return indexLastModified;
667N/A }
833N/A
1286N/A /**
1324N/A * Get the contents of a file or empty string if the file cannot be read.
1286N/A */
1461N/A @SuppressWarnings("resource")
1324N/A private static String getFileContent(File file) {
1324N/A if (file == null || ! file.canRead()) {
1324N/A return "";
1324N/A }
1324N/A FileReader fin = null;
1324N/A BufferedReader input = null;
1289N/A try {
1324N/A fin = new FileReader(file);
1324N/A input = new BufferedReader(fin);
1324N/A String line = null;
1324N/A StringBuilder contents = new StringBuilder();
1324N/A String EOL = System.getProperty("line.separator");
1324N/A while (( line = input.readLine()) != null) {
1324N/A contents.append(line).append(EOL);
1286N/A }
1324N/A return contents.toString();
1324N/A } catch (java.io.FileNotFoundException e) {
1436N/A /*
1436N/A * should usually not happen
1436N/A */
1324N/A } catch (java.io.IOException e) {
1327N/A logger.warning("failed to read include file '" + file.getName()
1327N/A + "': " + e.getMessage());
1324N/A } finally {
1324N/A if (input != null) {
1461N/A IOUtils.close(input);
1324N/A } else if (fin != null) {
1461N/A IOUtils.close(fin);
1324N/A }
1286N/A }
1324N/A return "";
1286N/A }
1286N/A
1299N/A /**
1324N/A * The name of the file relative to the <var>DATA_ROOT</var>, which should
1324N/A * be included into the footer of generated web pages.
1324N/A */
1324N/A public static final String FOOTER_INCLUDE_FILE = "footer_include";
1436N/A private transient String footer = null;
1324N/A /**
1324N/A * Get the contents of the footer include file.
1436N/A *
1324N/A * @return an empty string if it could not be read successfully, the
1324N/A * contents of the file otherwise.
1331N/A * @see #FOOTER_INCLUDE_FILE
1299N/A */
1299N/A public String getFooterIncludeFileContent() {
1324N/A if (footer == null) {
1324N/A footer = getFileContent(new File(getDataRoot(), FOOTER_INCLUDE_FILE));
1324N/A }
1324N/A return footer;
1299N/A }
1299N/A
1299N/A /**
1324N/A * The name of the file relative to the <var>DATA_ROOT</var>, which should
1324N/A * be included into the footer of generated web pages.
1324N/A */
1324N/A public static final String HEADER_INCLUDE_FILE = "header_include";
1436N/A private transient String header = null;
1324N/A /**
1324N/A * Get the contents of the footer include file.
1436N/A *
1324N/A * @return an empty string if it could not be read successfully, the
1324N/A * contents of the file otherwise.
1331N/A * @see #HEADER_INCLUDE_FILE
1299N/A */
1299N/A public String getHeaderIncludeFileContent() {
1324N/A if (header == null) {
1324N/A header = getFileContent(new File(getDataRoot(), HEADER_INCLUDE_FILE));
1324N/A }
1324N/A return header;
1299N/A }
1299N/A
1326N/A /**
1331N/A * The name of the file relative to the <var>DATA_ROOT</var>, which should
1331N/A * be included into the body of web app's "Home" page.
1331N/A */
1331N/A public static final String BODY_INCLUDE_FILE = "body_include";
1331N/A private transient String body = null;
1331N/A /**
1331N/A * Get the contents of the body include file.
1331N/A * @return an empty string if it could not be read successfully, the
1331N/A * contents of the file otherwise.
1331N/A * @see Configuration#BODY_INCLUDE_FILE
1331N/A */
1331N/A public String getBodyIncludeFileContent() {
1331N/A if (body == null) {
1331N/A body = getFileContent(new File(getDataRoot(), BODY_INCLUDE_FILE));
1435N/A }
1331N/A return body;
1299N/A }
1331N/A
1326N/A /**
1326N/A * The name of the eftar file relative to the <var>DATA_ROOT</var>, which
1326N/A * contains definition tags.
1326N/A */
1326N/A public static final String EFTAR_DTAGS_FILE = "index/dtags.eftar";
1436N/A private transient String dtagsEftar = null;
1326N/A /**
1326N/A * Get the eftar file, which contains definition tags.
1436N/A *
1326N/A * @return {@code null} if there is no such file, the file otherwise.
1326N/A */
1326N/A public File getDtagsEftar() {
1326N/A if (dtagsEftar == null) {
1326N/A File tmp = new File(getDataRoot() + "/" + EFTAR_DTAGS_FILE);
1326N/A if (tmp.canRead()) {
1421N/A try {
1421N/A dtagsEftar = tmp.getAbsolutePath();
1421N/A } catch (SecurityException e) {
1421N/A logger.warning(e.getLocalizedMessage());
1421N/A dtagsEftar = "";
1421N/A }
1326N/A } else {
1326N/A dtagsEftar = "";
1326N/A }
1326N/A }
1326N/A return dtagsEftar.isEmpty() ? null : new File(dtagsEftar);
1326N/A }
1326N/A
1461N/A /**
1461N/A * Get the fully quallified class name of the history database driver to use.
1461N/A * @return the database driver class name.
1461N/A */
833N/A public String getDatabaseDriver() {
833N/A return databaseDriver;
833N/A }
833N/A
1461N/A /**
1461N/A * Set the fully quallified class name of the history database driver to use.
1461N/A * @param databaseDriver the database driver class name to set.
1461N/A */
833N/A public void setDatabaseDriver(String databaseDriver) {
833N/A this.databaseDriver = databaseDriver;
833N/A }
833N/A
1461N/A /**
1461N/A * Get the JDBC connection URL to use to connect to the history database.
1461N/A * @return the JDBC connection URL to use.
1461N/A */
833N/A public String getDatabaseUrl() {
833N/A return databaseUrl;
833N/A }
833N/A
1461N/A /**
1461N/A * Set the JDBC connection URL to use to connect to the history database.
1461N/A * @param databaseUrl the JDBC connection URL to set.
1461N/A */
833N/A public void setDatabaseUrl(String databaseUrl) {
833N/A this.databaseUrl = databaseUrl;
833N/A }
833N/A
1461N/A /**
1461N/A * Get the optional file to be used to handover additional options to the
1461N/A * ctags command.
1461N/A * @return {@code null} if not set, the options filename otherwise.
1461N/A */
1416N/A public String getCtagsOptionsFile() {
1416N/A return ctagsOptionsFile;
1393N/A }
1393N/A
1461N/A /**
1461N/A * Set the file to be used to handover additional options to the ctags
1461N/A * command.
1461N/A * @param filename the options filename to use. Might be {@code null}.
1461N/A */
1416N/A public void setCtagsOptionsFile(String filename) {
1416N/A this.ctagsOptionsFile = filename;
1393N/A }
1393N/A
1461N/A /**
1461N/A * Get the pathnames of symlinks, which are allowed to be processed (e.g.
1461N/A * indexed, tokenized, etc.).
1461N/A * @return a possible empty set.
1461N/A */
1016N/A public Set<String> getAllowedSymlinks() {
1016N/A return allowedSymlinks;
1016N/A }
1016N/A
1461N/A /**
1461N/A * Set the pathnames of symlinks, which are allowed to be processed (e.g.
1461N/A * indexed, tokenized, etc.).
1461N/A * @param allowedSymlinks symlinks to allow. {@code null} means none.
1461N/A */
1016N/A public void setAllowedSymlinks(Set<String> allowedSymlinks) {
1461N/A if (allowedSymlinks == null) {
1461N/A this.allowedSymlinks.clear();
1461N/A } else {
1461N/A this.allowedSymlinks = new HashSet<String>(allowedSymlinks);
1461N/A }
1016N/A }
1016N/A
1461N/A /**
1461N/A * Check whether e-mail addresses should be obfuscated in the xref.
1461N/A * @return {@code true} if obfuscation is needed.
1461N/A */
1123N/A public boolean isObfuscatingEMailAddresses() {
1123N/A return obfuscatingEMailAddresses;
1123N/A }
1123N/A
1461N/A /**
1461N/A * Set whether e-mail addresses should be obfuscated in the xref.
1461N/A * @param obfuscate {@code true} if obfuscation is needed.
1461N/A */
1123N/A public void setObfuscatingEMailAddresses(boolean obfuscate) {
1123N/A this.obfuscatingEMailAddresses = obfuscate;
1123N/A }
1123N/A
1461N/A /**
1461N/A * Should status.jsp print internal settings, like paths and database
1461N/A * URLs?
1461N/A *
1461N/A * @return {@code true} if status.jsp should show the configuration.
1461N/A */
1125N/A public boolean isChattyStatusPage() {
1125N/A return chattyStatusPage;
1125N/A }
1125N/A
1461N/A /**
1461N/A * Set whether status.jsp should print internal settings.
1461N/A *
1461N/A * @param chattyStatusPage {@code true} if internal settings should be printed.
1461N/A */
1125N/A public void setChattyStatusPage(boolean chattyStatusPage) {
1125N/A this.chattyStatusPage = chattyStatusPage;
1125N/A }
1125N/A
234N/A /**
234N/A * Write the current configuration to a file
1436N/A *
234N/A * @param file the file to write the configuration into
234N/A * @throws IOException if an error occurs
234N/A */
234N/A public void write(File file) throws IOException {
1461N/A @SuppressWarnings("resource")
509N/A final FileOutputStream out = new FileOutputStream(file);
640N/A try {
640N/A this.encodeObject(out);
640N/A } finally {
1195N/A IOUtils.close(out);
640N/A }
639N/A }
937N/A
1461N/A /**
1461N/A * Serialize this instance into an XML formatted string.
1461N/A * @return this instance as xml string
1461N/A */
639N/A public String getXMLRepresentationAsString() {
639N/A ByteArrayOutputStream bos = new ByteArrayOutputStream();
639N/A this.encodeObject(bos);
639N/A return bos.toString();
639N/A }
937N/A
639N/A private void encodeObject(OutputStream out) {
640N/A XMLEncoder e = new XMLEncoder(new BufferedOutputStream(out));
640N/A e.writeObject(this);
640N/A e.close();
234N/A }
234N/A
1461N/A /**
1461N/A * Read the file containing a serialized {@link Configuration} instance and
1461N/A * return the marshalled instance.
1461N/A * @param file the file to read
1461N/A * @return the un-serialized Configuration instance represented by the file.
1461N/A * @throws IOException if the file cannot be read/decoded.
1461N/A */
1461N/A @SuppressWarnings("resource")
234N/A public static Configuration read(File file) throws IOException {
639N/A final FileInputStream in = new FileInputStream(file);
640N/A try {
640N/A return decodeObject(in);
640N/A } finally {
1195N/A IOUtils.close(in);
640N/A }
639N/A }
937N/A
1461N/A /**
1461N/A * Read the given string representing a in XML serialized {@link Configuration}
1461N/A * and return the marshalled instance.
1461N/A * @param xmlconfig serialized config to read.
1461N/A * @return the un-serialized Configuration instance represented by the string.
1461N/A * @throws IOException if the string cannot be decoded.
1461N/A */
1461N/A public static Configuration makeXMLStringAsConfiguration(String xmlconfig)
1461N/A throws IOException
1461N/A {
639N/A final Configuration ret;
639N/A final ByteArrayInputStream in = new ByteArrayInputStream(xmlconfig.getBytes());
639N/A ret = decodeObject(in);
639N/A return ret;
639N/A }
937N/A
639N/A private static Configuration decodeObject(InputStream in) throws IOException {
640N/A XMLDecoder d = new XMLDecoder(new BufferedInputStream(in));
640N/A final Object ret = d.readObject();
640N/A d.close();
509N/A
234N/A if (!(ret instanceof Configuration)) {
234N/A throw new IOException("Not a valid config file");
640N/A }
234N/A return (Configuration)ret;
234N/A }
639N/A
58N/A}