public void save(String filename) {
    if (propertiesMap == null) {

      // nothing to save, initialisation not complete

      return;
    }

    /**
     * Note - propertiesMap isn't synchronised! We'll clone the map now, because we need to modify
     * it. The BEncoding code will create a new map object (TreeMap) because it needs to be sorted,
     * so we might as well do it here too.
     */
    TreeMap<String, Object> properties_clone = propertiesMap.toTreeMap();

    // Remove any transient parameters.
    if (!this.transient_properties.isEmpty()) {
      properties_clone.keySet().removeAll(this.transient_properties);
    }

    FileUtil.writeResilientConfigFile(filename, properties_clone);

    List<COConfigurationListener> listeners_copy;

    synchronized (listenerz) {
      listeners_copy = new ArrayList<COConfigurationListener>(listenerz);
    }

    for (int i = 0; i < listeners_copy.size(); i++) {

      COConfigurationListener l = (COConfigurationListener) listeners_copy.get(i);

      if (l != null) {

        try {
          l.configurationSaved();

        } catch (Throwable e) {

          Debug.printStackTrace(e);
        }
      } else {

        Debug.out("COConfigurationListener is null");
      }
    }

    if (exported_parameters_dirty) {

      exportParameters();
    }
  }
  public void addAndFireListener(COConfigurationListener listener) {
    synchronized (listenerz) {
      listenerz.add(listener);
    }

    try {
      listener.configurationSaved();

    } catch (Throwable e) {

      Debug.printStackTrace(e);
    }
  }