// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.enterprise.adaptor;

import java.io.*;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.*;

/**
 * Configuration values for this program, like the GSA's hostname. Also several
 * knobs, or controls, for changing the behavior of the program.
 * <p>All available configuration:<br>
 * <style type="text/css"> td { padding-right:2em; } </style>
 * <table>
 * <tr><td align=center><b>required?</b></td>
 *     <td><b>name</b></td><td><b>meaning</b></td>
 * <tr><td> </td><td>gsa.acceptsDocControlsHeader </td><td>use 
 *      X-Gsa-Doc-Controls HTTP header with namespaced ACLs.
 *      Otherwise ACLs are sent without namespace and as metadata.
 *      If not set, then an attempt to compute from gsa.version is made.
 *      Defaults to true for 7.2.0-0 and later, and false for earlier,
 *      as defined by gsa.version.
 * <tr><td> </td><td>adaptor.fullListingSchedule </td><td> when to invoke 
 *     {@link Adaptor#getDocIds Adaptor.getDocIds}, in cron format (minute,
 *     hour,  day of month, month, day of week).  Defaults to 0 3 * * *
 * <tr><td> </td><td>adaptor.incrementalPollPeriodSecs </td><td> number
 *     of seconds between invocations of {@link
 *     PollingIncrementalLister#getModifiedDocIds
 *     PollingIncrementalLister.getModifiedDocIds}.    Defaults to 900
 * <tr><td> </td><td>adaptor.docContentTimeoutSecs </td><td> number of seconds
 *     adaptor has to complete sending content before it is interrupted. Timing
 *     starts when sending content starts. Defaults to 180
 * <tr><td> </td><td>adaptor.docHeaderTimeoutSecs </td><td> number of seconds
 *     adaptor has to start sending content before it is interrupted.
 *     Defaults to 30
 * <tr><td> </td><td>adaptor.pushDocIdsOnStartup </td><td> whether to invoke
 *     {@link Adaptor#getDocIds Adaptor.getDocIds} on process start
 *     (in addition to adaptor.fullListingSchedule).   Defaults to true
 * <tr><td> </td><td>docId.isUrl </td><td> say your adaptor's document ids
 *     are already URLs and avoid them being inserted into adaptor
       generated URLs.   Defaults to false
 * <tr><td> </td><td>feed.crawlImmediatelyBitEnabled </td><td> send bit telling
 *     GSA to crawl immediately.  Defaults to false
 * <tr><td> </td><td>feed.maxUrls </td><td> set max number of URLs included
 *     per feed file.    Defaults to 5000
 * <tr><td> </td><td>feed.name </td><td> source name used in feeds. Generated
 *     if not provided
 * <tr><td> </td><td>feed.noRecrawlBitEnabled </td><td> send bit telling
 *     GSA to crawl your documents only once.  Defaults to  false
 * <tr><td> </td><td>gsa.version </td><td> version number used to configure
 *     expected GSA features.  Defaults to acquiring from GSA.
 *     Uses 7.0.14-114 if acquiring fails.
 * <tr><td> </td><td>gsa.614FeedWorkaroundEnabled </td><td> enable detour
 *     around particular feed parsing failure found in GSA version 6.14 .
 *     Defaults to false
 * <tr><td> </td><td>gsa.70AuthMethodWorkaroundEnabled </td><td> send authmethod
 *     in feed files to workaround early GSA 7.0 bug. Defaults to false
 * <tr><td> </td><td>gsa.characterEncoding </td><td> character set used
 *     in feed files. Defaults to  UTF-8
 * <tr><td align="center"> yes </td><td>gsa.hostname </td><td> machine to
 *     send feed files to.  Process errors if not provided 
 * <tr><td> </td><td>gsa.samlEntityId </td><td> The SAML Entity ID that
 *     identifies the GSA. Defaults to
 *     http://google.com/enterprise/gsa/security-manager
 * <tr><td> </td><td>journal.reducedMem </td><td> avoid tracking per URL 
 *     information in RAM; suggested with over five hundred thousand documents.
 *     Defaults to true
 * <tr><td> </td><td>gsa.scoringType</td><td> type of relevance algorithm
 *      GSA utilizes to rank documents.  Either content or web.  Is sent
 *      when adaptor.sendDocControlHeader is true.  Defaults to content
 * <tr><td> </td><td>server.dashboardPort </td><td> port on adaptor's
 *     machine for accessing adaptor's dashboard.   Defaults to  5679
 * <tr><td> </td><td>server.docIdPath </td><td> part of URL preceding
 *     encoded document ids.  Defaults to  /doc/
 * <tr><td> </td><td>server.fullAccessHosts </td><td> hosts allowed access
 *     without authentication
 *     (certificates still needed when in secure mode).   Defaults to
 *     empty but implicitly contains gsa.hostname
 * <tr><td> </td><td>server.hostname </td><td>
 *     hostname of adaptor machine for URL generation. 
 *     The GSA will use this hostname to crawl the adaptor.
 *     Defaults to lowercase of automatically detected hostname
 * <tr><td> </td><td>server.keyAlias </td><td> keystore alias where
 *     encryption (public and private) keys are stored.
 *     Defaults to adaptor
 * <tr><td> </td><td>server.maxWorkerThreads </td><td> number of maximum
 *     simultenous retrievals  allowed.  Defaults to 16
 * <tr><td> </td><td>server.port </td><td> retriever port.  Defaults to 5678
 * <tr><td> </td><td>server.queueCapacity </td><td> max retriever queue size.
 *     Defaults to  160
 * <tr><td> </td><td>server.reverseProxyPort </td><td> port used in
 *     retriever URLs (in case requests
 *     are routed through a reverse proxy).  Defaults to server.port
 * <tr><td> </td><td>server.reverseProxyProtocol </td><td> either http or https,
 *     depending on  proxy traffic.  Defaults to https in secure
 *     mode and http otherwise
 * <tr><td> </td><td>server.samlEntityId </td><td> The SAML Entity ID that the
 *     Adaptor will use to identity itself. Defaults to
 *     http://google.com/enterprise/gsa/adaptor
 * <tr><td> </td><td>server.secure </td><td> enables https and certificate
 *     checking. Defaults to false
 * <tr><td> </td><td>server.useCompression </td><td> compress retrieval
 *     responses. Defaults to true
 * <tr><td> </td><td>transform.acl.X </td><td> where X is an integer, match
 *     and modify principals as described. Defaults no modifications
 * <tr><td> </td><td>transform.pipeline </td><td> sequence of
 *     transformation steps.  Defaults to no-pipeline
 * </table>
 */
public class Config {
  private static final Logger log = Logger.getLogger(Config.class.getName());

  /** Configuration keys whose default value is {@code null}. */
  private final Set<String> noDefaultConfig = new HashSet<String>();
  /** Default configuration values. */
  private final Properties defaultConfig = new Properties();
  /** Overriding configuration values loaded from command line. */
  // Reads require no additional locks, but modifications require lock on 'this'
  // to prevent lost updates.
  private volatile Properties config = new Properties(defaultConfig);
  /**
   * The actual config file in use, or {@code null} if none have been loaded.
   */
  private File configFile;
  private long configFileLastModified;
  private List<ConfigModificationListener> modificationListeners
      = new CopyOnWriteArrayList<ConfigModificationListener>();
  /**
   * Map from config key to computer that generates the value for the key. These
   * generated values are generally due to one value being formed from other
   * values by default.
   */
  private Map<String, ValueComputer> computeMap
      = new HashMap<String, ValueComputer>();

  public Config() {
    String hostname = null;
    try {
      hostname = InetAddress.getLocalHost().getCanonicalHostName();
      hostname = hostname.toLowerCase(Locale.ENGLISH);  // work around GSA 7.0
    } catch (UnknownHostException ex) {
      // Ignore
    }
    addKey("server.hostname", hostname);
    addKey("server.port", "5678");
    addKey("server.reverseProxyPort", "GENERATE", new ValueComputer() {
          public String compute(String rawValue) {
            if ("GENERATE".equals(rawValue)) {
              return getValue("server.port");
            }
            return rawValue;
          }
        });
    addKey("server.reverseProxyProtocol", "GENERATE", new ValueComputer() {
          public String compute(String rawValue) {
            if ("GENERATE".equals(rawValue)) {
              return isServerSecure() ? "https" : "http";
            }
            return rawValue;
          }
        });
    addKey("server.dashboardPort", "5679");
    addKey("server.docIdPath", "/doc/");
    addKey("server.fullAccessHosts", "");
    addKey("server.secure", "false");
    addKey("server.keyAlias", "adaptor");
    addKey("server.maxWorkerThreads", "16");
    // A queue that takes one second to drain, assuming 16 threads and 100 ms
    // for each request.
    addKey("server.queueCapacity", "160");
    addKey("server.useCompression", "true");
    addKey("server.samlEntityId", "http://google.com/enterprise/gsa/adaptor");
    addKey("gsa.hostname", null);
    addKey("gsa.characterEncoding", "UTF-8");
    addKey("gsa.version", "GENERATE");
    addKey("gsa.614FeedWorkaroundEnabled", "false");
    addKey("gsa.70AuthMethodWorkaroundEnabled", "false");
    addKey("gsa.samlEntityId",
        "http://google.com/enterprise/gsa/security-manager");
    addKey("gsa.scoringType", "content");
    addKey("docId.isUrl", "false");
    addKey("feed.name", "GENERATE", new ValueComputer() {
          public String compute(String rawValue) {
            if ("GENERATE".equals(rawValue)) {
              return "adaptor_" + getValue("server.hostname").replace('.', '-')
                  + "_" + getValue("server.port");
            }
            return rawValue;
          }
        });
    addKey("feed.noRecrawlBitEnabled", "false");
    addKey("feed.crawlImmediatelyBitEnabled", "false");
    //addKey("feed.noFollowBitEnabled", "false");
    addKey("feed.maxUrls", "5000");
    addKey("adaptor.pushDocIdsOnStartup", "true");
    // 3:00 AM every day.
    addKey("adaptor.fullListingSchedule", "0 3 * * *");
    // 15 minutes.
    addKey("adaptor.incrementalPollPeriodSecs", "900");
    addKey("adaptor.docContentTimeoutSecs", "180");
    addKey("adaptor.docHeaderTimeoutSecs", "30");
    addKey("transform.pipeline", "");
    addKey("journal.reducedMem", "true");
    addKey("gsa.acceptsDocControlsHeader", "GENERATE", new ValueComputer() {
          public String compute(String rawValue) {
            if (!"GENERATE".equals(rawValue)) {
              log.log(Level.FINE,
                  "returning raw gsa.acceptsDocControlsHeader: {0}", rawValue);
              return rawValue;
            }
            String ver = getValue("gsa.version");
            if ("GENERATE".equals(ver)) {
              throw new IllegalStateException("gsa.version not yet available");
            } else {
              boolean computed = new GsaVersion(ver).isAtLeast("7.2.0-0");
              log.log(Level.FINE,
                  "gsa.acceptsDocControlsHeader computed {0}", computed);
              return "" + computed;
            }
          }
        });
  }

  public Set<String> getAllKeys() {
    return config.stringPropertyNames();
  }

  /* Preferences requiring you to set them: */
  /**
   * Required to be set: GSA machine to send document ids to. This is the
   * hostname of your GSA on your network.
   */
  String getGsaHostname() {
    return getValue("gsa.hostname");
  }

  /* Preferences suggested you set them: */

  String getFeedName() {
    return getValue("feed.name");
  }

  /**
   * Suggested to be set: Local port, on this computer, onto which requests from
   * GSA come in on.
   */
  int getServerPort() {
    return Integer.parseInt(getValue("server.port"));
  }

  /**
   * The port that should be used in feed file and other references to the
   * adaptor. This does not affect the actual port the adaptor uses.
   */
  int getServerReverseProxyPort() {
    return Integer.parseInt(getValue("server.reverseProxyPort"));
  }

  /**
   * The protocol that should be used in feed files and other references to the
   * adaptor. This does not affect the actual protocol the adaptor uses.
   */
  String getServerReverseProxyProtocol() {
    return getValue("server.reverseProxyProtocol");
  }

  /**
   * Local port, on this computer, from which the dashboard is served.
   */
  int getServerDashboardPort() {
    return Integer.parseInt(getValue("server.dashboardPort"));
  }

  /* More sophisticated preferences that can be left
   unmodified for simple deployment and initial POC: */
  /**
   * Optional (default false): If your DocIds are already valid URLs you can
   * have this method return true and they will be sent to GSA unmodified. If
   * your DocId is like http://procurement.corp.company.com/internal/011212.html
   * you can turn this true and that URL will be handed to the GSA.
   *
   * <p>By default DocIds are URL encoded and prefixed with http:// and this
   * host's name and port.
   */
  boolean isDocIdUrl() {
    return Boolean.parseBoolean(getValue("docId.isUrl"));
  }

  /** Default is lowercase of InetAddress.getLocalHost().getHostName(). */
  String getServerHostname() {
    String hostname = getValue("server.hostname");
    log.log(Level.FINER, "server hostname: {0}", hostname);
    return hostname;
  }

  /**
   * Comma-separated list of IPs or hostnames that can retrieve content without
   * authentication checks. The GSA's hostname is implicitly in this list.
   *
   * <p>When in secure mode, clients are requested to provide a client
   * certificate. If the provided client certificate is valid and the Common
   * Name (CN) of the Subject is in this list (case-insensitively), then it is
   * given access.
   *
   * <p>In non-secure mode, the hostnames in this list are resolved to IPs at
   * startup and when a request is made from one of those IPs the client is
   * given access.
   */
  String[] getServerFullAccessHosts() {
    return getValue("server.fullAccessHosts").split(",");
  }

  /**
   * Optional: Returns this host's base URI which other paths will be resolved
   * against. It is used to construct URIs to provide to the GSA for it to
   * contact this server for various services.
   *
   * <p>It contains the protocol, hostname, and port.
   */
  URI getServerBaseUri() {
    return URI.create(getServerReverseProxyProtocol() + "://"
        + getServerHostname() + ":" + getServerReverseProxyPort());
  }

  /**
   * Optional: Path below {@link #getServerBaseUri(DocId)} where documents are
   * namespaced. Generally, should be at least {@code "/"} and end with a slash.
   */
  String getServerDocIdPath() {
    return getValue("server.docIdPath");
  }

  /**
   * Whether full security should be enabled. When {@code true}, the adaptor is
   * locked down using HTTPS, checks certificates, and generally behaves in a
   * fully-secure manner. When {@code false} (default), the adaptor serves
   * content over HTTP and is unable to authenticate users (all users are
   * treated as anonymous).
   *
   * <p>The need for this setting is because when enabled, security requires a
   * reasonable amount of configuration and know-how. To provide easy
   * out-of-the-box execution, this is disabled by default.
   */
  boolean isServerSecure() {
    return Boolean.parseBoolean(getValue("server.secure"));
  }

  /**
   * The alias in the keystore that has the key to use for encryption.
   */
  String getServerKeyAlias() {
    return getValue("server.keyAlias");
  }

  /**
   * The maximum number of worker threads to use to respond to document
   * requests. 
   */
  int getServerMaxWorkerThreads() {
    return Integer.parseInt(getValue("server.maxWorkerThreads"));
  }

  /**
   * The maximum request queue length.
   */
  int getServerQueueCapacity() {
    return Integer.parseInt(getValue("server.queueCapacity"));
  }

  String getServerSamlEntityId() {
    return getValue("server.samlEntityId");
  }

  boolean isServerToUseCompression() {
    return Boolean.parseBoolean(getValue("server.useCompression"));
  }

  boolean doesGsaAcceptDocControlsHeader() {
    return Boolean.parseBoolean(getValue("gsa.acceptsDocControlsHeader"));
  }

  /**
   * Optional (default false): Adds no-recrawl bit with sent records in feed
   * file. If connector handles updates and deletes then GSA does not have to
   * recrawl periodically to notice that a document is changed or deleted.
   */
  boolean isFeedNoRecrawlBitEnabled() {
    return Boolean.getBoolean(getValue("feed.noRecrawlBitEnabled"));
  }

  /**
   * Optional (default false): Adds crawl-immediately bit with sent records in
   * feed file.  This bit makes the sent URL get crawl priority.
   */
  boolean isCrawlImmediatelyBitEnabled() {
    return Boolean.parseBoolean(getValue("feed.crawlImmediatelyBitEnabled"));
  }

  /**
   * Whether the default {@code main()} should automatically start pushing all
   * document ids on startup. Defaults to {@code true}.
   */
  boolean isAdaptorPushDocIdsOnStartup() {
    return Boolean.parseBoolean(getValue("adaptor.pushDocIdsOnStartup"));
  }

  /**
   * Cron-style format for describing when the adaptor should perform full
   * listings of {@code DocId}s. Multiple times can be specified by separating
   * them with a '|' (vertical bar).
   */
  String getAdaptorFullListingSchedule() {
    return getValue("adaptor.fullListingSchedule");
  }

  long getAdaptorIncrementalPollPeriodMillis() {
    return Long.parseLong(getValue("adaptor.incrementalPollPeriodSecs")) * 1000;
  }

  long getAdaptorDocHeaderTimeoutMillis() {
    return Long.parseLong(getValue("adaptor.docHeaderTimeoutSecs")) * 1000;
  }

  long getAdaptorDocContentTimeoutMillis() {
    return Long.parseLong(getValue("adaptor.docContentTimeoutSecs")) * 1000;
  }

  /**
   * Returns a list of maps correspending to each transform in the pipeline.
   * Each map is the configuration entries for that transform. The 'name'
   * configuration entry is added in each map based on the name provided by the
   * user.
   */
  List<Map<String, String>> getTransformPipelineSpec() {
    return getListOfConfigs("transform.pipeline");
  }

  /**
   * Returns a list of maps corresponding to each item of the comma-separated
   * value of {@code key}. Each map is the configuration entries for that item
   * in the list. The 'name' configuration entry is added in each map based on
   * the name provided by the user.
   *
   * <p>As an example, provided the following config:
   * <pre><code>adaptor.servers=server1,fluttershy , rainbowDash
   *adaptor.servers.fluttershy.hostname=fluttershy
   *adaptor.servers.fluttershy.port=42
   *adaptor.servers.server1.hostname=applejack
   *adaptor.servers.server1.port=314
   *adaptor.servers.rainbowDash.hostname=rainbowdash
   *adaptor.servers.rainbowDash.port=159
   *adaptor.servers.rainbowDash.name=20% cooler
   *adaptor.servers.derpy.hostname=hooves</code></pre>
   *
   * <p>And calling:
   * <pre><code>config.getConfigList("adaptor.servers");</code></pre>
   *
   * <p>Returns:
   * <pre><code>[{
   *  "hostname": "applejack",
   *  "port": "42",
   *  "name": "server1",
   *}, {
   *  "hostname": "fluttershy",
   *  "port": "314",
   *  "name": "fluttershy",
   *}, {
   *  "hostname": "rainbowdash",
   *  "port": "159",
   *  "name": "raindowDash",
   *}]</code></pre>
   */
  public synchronized List<Map<String, String>>
      getListOfConfigs(String key) {
    String configValue = getValue(key).trim();
    if ("".equals(configValue)) {
      return Collections.emptyList();
    }
    String[] items = getValue(key).split(",");
    List<Map<String, String>> listOfMaps
        = new ArrayList<Map<String, String>>(items.length);
    for (String item : items) {
      item = item.trim();
      if ("".equals(item)) {
        throw new RuntimeException("Invalid format: " + configValue);
      }
      Map<String, String> params
          = getValuesWithPrefix(key + "." + item + ".");
      params.put("name", item);
      listOfMaps.add(params);
    }
    return listOfMaps;
  }

  boolean isJournalReducedMem() {
    return Boolean.parseBoolean(getValue("journal.reducedMem"));
  }

// TODO(pjo): Implement on GSA
//  /**
//   * Optional (default false): Adds no-follow bit with sent records in feed
//   * file. No-follow means that if document content has links they are not
//   * followed.
//   */
//  boolean isNoFollowBitEnabled() {
//    return Boolean.parseBoolean(getValue("feed.noFollowBitEnabled"));
//  }

  /* Preferences expected to never change: */

  /** Provides the character encoding the GSA prefers. */
  Charset getGsaCharacterEncoding() {
    return Charset.forName(getValue("gsa.characterEncoding"));
  }

  String getGsaVersion() {
    return getValue("gsa.version");
  }

  boolean isGsa614FeedWorkaroundEnabled() {
    return Boolean.parseBoolean(getValue("gsa.614FeedWorkaroundEnabled"));
  }

  boolean isGsa70AuthMethodWorkaroundEnabled() {
    return Boolean.parseBoolean(getValue("gsa.70AuthMethodWorkaroundEnabled"));
  }

  String getGsaSamlEntityId() {
    return getValue("gsa.samlEntityId");
  }

  /**
   * Provides max number of URLs (equal to number of document ids) that are sent
   * to the GSA per feed file.
   */
  int getFeedMaxUrls() {
    return Integer.parseInt(getValue("feed.maxUrls"));
  }

  /**
   * Provides the type of algorithm GSA is to use to rank documents sent by
   * adaptor.
   */
  String getScoringType() {
    return getValue("gsa.scoringType");
  }

  /**
   * Load user-provided configuration file.
   */
  public synchronized void load(String configFile) throws IOException {
    load(new File(configFile));
  }

  /**
   * Load user-provided configuration file.
   */
  public synchronized void load(File configFile) throws IOException {
    this.configFile = configFile;
    configFileLastModified = configFile.lastModified();
    Reader reader = createReader(configFile);
    try {
      load(reader);
    } finally {
      reader.close();
    }
  }

  /**
   * Load user-provided configuration file, replacing any previously loaded file
   * configuration.
   */
  private void load(Reader configFile) throws IOException {
    Properties newConfigFileProperties = new Properties(defaultConfig);
    newConfigFileProperties.load(configFile);

    Config fakeOldConfig;
    Set<String> differentKeys;
    synchronized (this) {
      // Create replacement config.
      Properties newConfig = new Properties(newConfigFileProperties);
      for (Object o : config.keySet()) {
        newConfig.put(o, config.get(o));
      }

      // Find differences.
      differentKeys = findDifferences(config, newConfig);

      if (differentKeys.isEmpty()) {
        log.info("No configuration changes found");
        return;
      }

      validate(newConfig);

      fakeOldConfig = new Config();
      fakeOldConfig.config = config;
      this.config = newConfig;
    }
    log.info("New configuration file loaded");
    fireConfigModificationEvent(fakeOldConfig, differentKeys);
  }

  Reader createReader(File configFile) throws IOException {
    return new InputStreamReader(new BufferedInputStream(
        new FileInputStream(configFile)), Charset.forName("UTF-8"));
  }

  /**
   * @return {@code true} if configuration file was modified.
   */
  public boolean ensureLatestConfigLoaded() throws IOException {
    synchronized (this) {
      if (configFile == null || !configFile.exists() || !configFile.isFile()) {
        return false;
      }
      // Check for modifications.
      long newLastModified = configFile.lastModified();
      if (configFileLastModified == newLastModified || newLastModified == 0) {
        return false;
      }
      log.info("Noticed modified configuration file");

      load(configFile);
    }
    return true;
  }

  private Set<String> findDifferences(Properties config, Properties newConfig) {
    Set<String> differentKeys = new HashSet<String>();
    Set<String> names = new HashSet<String>();
    names.addAll(config.stringPropertyNames());
    names.addAll(newConfig.stringPropertyNames());
    for (String name : names) {
      String value = config.getProperty(name);
      String newValue = newConfig.getProperty(name);
      boolean equal = (value == null && newValue == null)
          || (value != null && value.equals(newValue));
      if (!equal) {
        differentKeys.add(name);
      }
    }
    return differentKeys;
  }

  public void validate() {
    validate(config);
  }

  private void validate(Properties config) {
    Set<String> unset = new HashSet<String>();
    for (String key : noDefaultConfig) {
      if (config.getProperty(key) == null) {
        unset.add(key);
      }
    }
    if (unset.size() != 0) {
      throw new IllegalStateException("Missing configuration values: " + unset);
    }
  }

  /**
   * Get a configuration value exactly as provided in configuration. Generally,
   * {@link #getValue} should be used instead of this method.
   *
   * @return raw non-{@code null} value of {@code key}
   * @throws IllegalStateException if {@code key} has no value
   */
  public String getRawValue(String key) {
    String value = config.getProperty(key);
    if (value == null) {
      throw new IllegalStateException(MessageFormat.format(
          "You must set configuration key ''{0}''.", key));
    }
    return value;
  }

  /**
   * Get a configuration value as computed based on the configuration. Some
   * configuration values can be generated from other values. This method
   * returns that computed configuration value instead of the raw value provided
   * in configuration. This method should be preferred over {@link
   * #getRawValue}.
   *
   * @return non-{@code null} value of {@code key}
   * @throws IllegalStateException if {@code key} has no value
   */
  public String getValue(String key) {
    String value = getRawValue(key);
    ValueComputer computer = computeMap.get(key);
    if (computer != null) {
      value = computer.compute(value);
    }
    return value;
  }

  /**
   * Gets all configuration values that begin with {@code prefix}, returning
   * them as a map with the keys having {@code prefix} removed.
   */
  public synchronized Map<String, String> getValuesWithPrefix(String prefix) {
    Map<String, String> values = new HashMap<String, String>();
    for (String key : config.stringPropertyNames()) {
      if (!key.startsWith(prefix)) {
        continue;
      }
      values.put(key.substring(prefix.length()), config.getProperty(key));
    }
    return values;
  }

  /**
   * Add configuration key. If {@code defaultValue} is {@code null}, then no
   * default value is used and the user must provide one.
   */
  public synchronized void addKey(String key, String defaultValue) {
    if (defaultConfig.containsKey(key) || noDefaultConfig.contains(key)) {
      throw new IllegalStateException("Key already added: " + key);
    }
    if (defaultValue == null) {
      noDefaultConfig.add(key);
    } else {
      defaultConfig.setProperty(key, defaultValue);
    }
  }

  synchronized void addKey(String key, String defaultValue,
      ValueComputer computer) {
    addKey(key, defaultValue);
    computeMap.put(key, computer);
  }

  /**
   * Change the default value of a preexisting configuration key. If {@code
   * defaultValue} is {@code null}, then no default is used and the user must
   * provide one.
   */
  public synchronized void overrideKey(String key, String defaultValue) {
    if (!defaultConfig.containsKey(key) && !noDefaultConfig.contains(key)) {
      log.log(Level.WARNING, "Overriding unknown configuration key: {0}", key);
    }
    defaultConfig.remove(key);
    noDefaultConfig.remove(key);
    if (defaultValue == null) {
      noDefaultConfig.add(key);
    } else {
      defaultConfig.setProperty(key, defaultValue);
    }
  }

  /**
   * Manually set a configuration value. Depending on when called, it can
   * override a user's configuration, which should be avoided.
   */
  synchronized void setValue(String key, String value) {
    config.setProperty(key, value);
  }

  void addConfigModificationListener(
      ConfigModificationListener listener) {
    modificationListeners.add(listener);
  }

  void removeConfigModificationListener(
      ConfigModificationListener listener) {
    modificationListeners.remove(listener);
  }

  private void fireConfigModificationEvent(Config oldConfig,
                                           Set<String> modifiedKeys) {
    ConfigModificationEvent ev
        = new ConfigModificationEvent(this, oldConfig, modifiedKeys);
    for (ConfigModificationListener listener : modificationListeners) {
      try {
        listener.configModified(ev);
      } catch (Exception ex) {
        log.log(Level.WARNING,
                "Unexpected exception. Consider filing a bug.", ex);
      }
    }
  }

  interface ValueComputer {
    /**
     * Computes the effective value of a configuration value provided the
     * literal value provided in configuration.
     */
    public String compute(String rawValue);
  }
}
