Last modified 13 years ago Last modified on 06/17/09 11:34:56

Error: Macro BackLinksMenu(None) failed
compressed data is corrupt

Error: Macro TicketQuery(summary=PLUGIN_SUPPORT_LIB_CONFIGURING_R1, format=table, col=summary|owner|status|type|component|priority|effort|importance, rows=description|analysis_owners|analysis_reviewers|analysis_score|design_owners|design_reviewers|design_score|implementation_owners|implementation_reviewers|implementation_score|test_owners|test_reviewers|test_score|) failed
current transaction is aborted, commands ignored until end of transaction block



The goal of this task is to provide ability to load and save configuration settings that are not defined by skins. For example, bug reporting requires user's e-mail address to be persisted.

Task requirements

  • Configuration settings are stored as pairs (key, value).
  • Loading and saving configuration settings should be easy and made in uniform way:
    • get : key -> value - reads the value from configuration file.
    • set : key, value - updates the value so any part of Sophie that depends on it is updated.
  • Convention for configuration files:
    • Configuration files can be stored in distrib/conf/ directory of the corresponding plugin.
    • Their names should be unique for the application.
      • Use the name of the corresponding Sophie module, for example:
        • distrib/conf/org.sophie2.main.layout.mydoggy.conf
        • distrib/conf/org.sophie2.main.layout.mydoggy/some_name
    • Configuration files are saved in XML format.
    • Keys should be unique in a given configuration file, but there's no need to be globally unique, since the file names are unique.
  • Make at least one of the following settings to be persisted in configuration files:
    • User's e-mail address in the bug report form.
    • Main window's size, location and state (maximized/normal).
    • Current skin - default or alternative.

Task result

  • Source code.

Implementation idea

  • This functionality has much in common with skins, but cannot be implemented as skins. So create a new module.
  • Create a singleton class ConfigurationManager (or something else) that has the described get and set methods.
  • Create a class Configuration that represents a single configuration file.
    • Use list of ListEntrys that stores all key-value pairs in that file.

  • Create a generic class ConfigKey that encapsulates all of the information about a key:
    • key name
    • configuration file
    • default value (if the key is not present in the file)
    • schema (for the persistence)
  • ConfigKeys should be defined as constants in the code, for example:
    • public static final ConfigKey USER_EMAIL = ...;
    • email = ConfigurationManager.get().get(USER_EMAIL);

How to demo

  • Open Sophie.
  • Open the bug report form (in Help menu) and enter a valid e-mail address.
  • Close the form.
  • Restart Sophie.
  • Open the bug report and show the saved e-mail address.


  • New module org.sophie2.base.config.
  • Immutable generic class ConfigKey<T> that encapsulates all of the information about a key:
    • name (of the key) - String
    • configuration file - String - relative path. For example, if the file is "distrib/conf/a/b.conf", this should be "a/b.conf".
    • default value (if the key is not present in the file) - T
    • schema (for the persistence) - String, for example "imm:int|storage|decimal"
  • Class BaseConfigModule.
    • Extension point of type ConfigKey<?>.
  • Class ConfigEntry that extends ListEntry
    • This class represents a key-value pair in a configuration file.
    • Override getKey to return a ConfigKey.
  • Class Configuration - represents a single configuration file.
    • configuration file - File
    • list property of ConfigEntrys that stores all key-value pairs in that file.
    • T getValue(ConfigKey<T> key) - searches the list for a given entry and returns the corresponding value or the default value for the key.
    • void setValue(ConfigKey<T> key, T value) - sets the value in the list.
  • Package org.sophie2.base.config.persistence
  • Class ConfigurationStoragePersister that loads/saves configuration files from/to Storage.
    • Use the following structure for the storage, where "value" is the storage for the value of the configuration key, created with the according persister:
      • entry
        • key - attribute
        • value - text content of entry
      • entry
        • key - attribute
        • value - text content of entry
    • Schema: "configuration|storage|conf"
    • When reading, iterate over all registered extensions - config keys - for the given configuration file.
  • Class ConfigurationFilePersister that loads/saves Storage from/to *.conf files.
    • Use the same structure as the storage for the XML file.
      • Name the root tag "configuration".
    • Schema: "storage|xml|conf"
  • Register the persisters as extensions.
  • Singleton class ConfigurationManager.
    • list of entries (String, Configuration), which maps Configuration objects to configuration file names.
    • T getValue(ConfigKey<T> key)
      • Given the file name in the key, finds the corresponding Configuration and then returns the result of Configuration.getValue.
    • setValue(ConfigKey<T> key, T value)
      • Given the file name in the key, finds the corresponding Configuration and sets the new value for that key.
    • When a Configuration for a given file is constructed, all entries are read from that file and stored in the list.
    • Method saveAll that saves all configurations using the persisters.
      • This method should be invoking when stopping the base.config module.
  • In BugReportLogic
    • Remove the file "distrib/email" and create a new one "distrib/conf/".
    • Create a ConfigKey userEmail and add it as an extension for the help module.
    • Remove the method readEmail and use getValue in ConfigurationManager.
    • In SAVE_EMAIL use setValue in ConfigurationManager.


Merged to the trunk in [3539].


(Place the testing results here.)


(Write comments for this or later revisions here.)