/**
   * Performs a reload operation if necessary. This method is called on each access of this
   * configuration. It asks the associated reloading strategy whether a reload should be performed.
   * If this is the case, the configuration is cleared and loaded again from its source. If this
   * operation causes an exception, the registered error listeners will be notified. The error event
   * passed to the listeners is of type <code>EVENT_RELOAD</code> and contains the exception that
   * caused the event.
   */
  public void reload() {
    synchronized (reloadLock) {
      if (noReload == 0) {
        try {
          enterNoReload(); // avoid reentrant calls

          if (strategy.reloadingRequired()) {
            if (getLogger().isInfoEnabled()) {
              getLogger().info("Reloading configuration. URL is " + getURL());
            }
            fireEvent(EVENT_RELOAD, null, getURL(), true);
            setDetailEvents(false);
            boolean autoSaveBak = this.isAutoSave(); // save the current state
            this.setAutoSave(false); // deactivate autoSave to prevent information loss
            try {
              clear();
              load();
            } finally {
              this.setAutoSave(autoSaveBak); // set autoSave to previous value
              setDetailEvents(true);
            }
            fireEvent(EVENT_RELOAD, null, getURL(), false);

            // notify the strategy
            strategy.reloadingPerformed();
          }
        } catch (Exception e) {
          fireError(EVENT_RELOAD, null, null, e);
          // todo rollback the changes if the file can't be reloaded
        } finally {
          exitNoReload();
        }
      }
    }
  }
 /**
  * Sends an event to all registered listeners. This implementation ensures that no reloads are
  * performed while the listeners are invoked. So infinite loops can be avoided that can be caused
  * by event listeners accessing the configuration's properties when they are invoked.
  *
  * @param type the event type
  * @param propName the name of the property
  * @param propValue the value of the property
  * @param before the before update flag
  */
 protected void fireEvent(int type, String propName, Object propValue, boolean before) {
   enterNoReload();
   try {
     super.fireEvent(type, propName, propValue, before);
   } finally {
     exitNoReload();
   }
 }
  /**
   * Returns an <code>Iterator</code> with the keys contained in this configuration. This
   * implementation performs a reload if necessary before obtaining the keys. The <code>Iterator
   * </code> returned by this method points to a snapshot taken when this method was called. Later
   * changes at the set of keys (including those caused by a reload) won't be visible. This is
   * because a reload can happen at any time during iteration, and it is impossible to determine how
   * this reload affects the current iteration. When using the iterator a client has to be aware
   * that changes of the configuration are possible at any time. For instance, if after a reload
   * operation some keys are no longer present, the iterator will still return those keys because
   * they were found when it was created.
   *
   * @return an <code>Iterator</code> with the keys of this configuration
   */
  public Iterator getKeys() {
    reload();
    List keyList = new LinkedList();
    enterNoReload();
    try {
      for (Iterator it = super.getKeys(); it.hasNext(); ) {
        keyList.add(it.next());
      }

      return keyList.iterator();
    } finally {
      exitNoReload();
    }
  }