This is the object responcible the data. It is simple and has absolutely nothing to do with the gui. It is important because it keeps a list of Contacts and Services. Contacts must have a service type in them. This service type is the name of a service. It is not the generic name of the type of services (such as "Private Messenger") but the specific name.
This is the gui! It reads and write an FastMessengerConfiguration object as well as maintains the basic GUI.
The tree is the most obvious component of the GUI. It is comprised of 2 levels, the services level and the contact level. The service level is the first level of the tree. It consists of the service names. Inside each service is a list of contacts. These contacts may be contacted by the service's client code. Note that some services may not have a client component and so calling contacts that reside under them will result in nothing happening.
The service layer must consist of only ServiceTreeNode objects.
The contact layer must consist of only ContactTreeNode objects. Alter either of these practices and you'll see a whole lot of ClassCastExceptions.
The user may read from the FMNexus object all they like, as that object should be kept up to date with the FastMessenger object containing it. However, users should not alter the FMNexus and expect those changes to be reflected in the FastMessenger object. Infact, deleting information from the FMNexus tha the FastMessenger object expects to be present may cause unstable behavior.
Configuraions are stored using NetObject lists, ListObject objects. This makes for easy storing and safe reading of configurations but adds essentially a layer that can become inconsistant with the acctual settings in effect. Also the user must enter data into a dialog box which must by syncronized with the configuration object. Following are the details of how this is managed.
If the configuration object holds all the configurations for a system and the configuration object is the only manipulator of the system, will not then the system always be consistent with the configuration object? The answer is, of course, yes but this is in a perfect work. In the specific instance of the FastMessenger object the node ID and port may change as may the contact list and the configuration object will never be told about it. Thus, while the configuration object does not read but only dictates some values, such as log file names and what services to start running with, it does neat to read configurations in from the running FastMessenger object. This is done before a dialog is presented and before the configuration is saved. Note that the FastMessenger object calls for this. It is not automatically done by the FastMessengerConfiguration.
Related to this is the dialog box where the user enters most of the settings. The dialog box has 2 methods of critical interest. The push and pull methods push and pull configuration settings to and from the configuration object out of and in to the GUI components. If the dialog is canceled, then the push to the configuration object is not performed nor is the required reapplication of the configuration object to the running system.
Reapplying configurations is somewhat tricky in that there is no nice clean way to generalize it. If a node port or encryption value changes, we must restart the node's server componenet. If a log file changes we must disgard all previous log handlers and add the new ones.
Other changes are far more simple such as reconfiguring services. Services are added and deletted while the user is still in the gui, thus there is no need to detect which ones must be added and which ones must be deletted. Each server must apply its configurations to themselves and offer them up for addition into the configuration object. In this particular case the FastMessengerConfiguration object only acts as a broker which hold a single ListObject named after each service's name which it retrieves from the service and will return to the service the next time it is created.
How, though, does a developer add a new configuration option. Cosider how the Log-to-Console option was added.
First, an object and name was put in the FastMessengerConfiguration object. Specifically, LOG_TO_CONSOLE was created as an object constant and where the defaults are created a line for this value was added. Also the apply method was changed to look for this value and change the FastMessagingObject accordingly. We could also have tried to change the readConfig(FastMessenger) method if we thought that this value might change apart from the configuration object, but we really don't care about tracking that change if it even happens. Logging preferences are just not very dynamic and don't get reconfigured all over the system, typically.
The next step was to give the Log-to-Console option a manifestation in the big configuration panel. First we made a JCheckBox and added it to the JPanel and the GridBagLayout where we wanted it. Then we added a line in the push and pull methods to write this value to the configuration object and read it from the configuration object. That's it!
You can see that by paying the cost for having our configurations divorced from the GUI, we can also invisibly track things such as uptime, window sizes and placement, best peer connections, and last-open connections. Note, we don't track all this yet, but it would be nice.