2016/12/13 - Apache Etch has been retired.

For more information, please explore the Attic.

Configuration Service

The configuration service (and corresponding local components) allow for remote administration of a service or client. This remote administration is essential for enterprise deployments. The template main programs that etch creates for you have configuration information (service and listener uris) built into the code. If you go too far down this path then your programs will be hard to deploy as they will need to be recompiled to change settings. There is a natural evolutionary path often taken:

At each level above we are trading off convenience for manageability. The last level is the most manageable for the operators, while the first level is the most convenient for the programmers.

The best practical systems often use a combination of the above techniques to achieve the goals of the project.

Another direction taken on configuration is whether the configuration information is static or dynamic. Static information is fixed once the program starts, dynamic configuration can change while the program is running. Consider a running service listener with some configured information for the listener uri and also the names, passwords, and other information for the users. Suppose it is statically configured. Some user information needs to be updated. The service must be stopped, the configuration updated, and the service started again. During that time the service is unavailable, and sometimes work in progress when the service went down is lost. Dynamic configuration would have allowed that service to remain available while the information was being updated.

Requirements

One of the goals of a configuration service should be to not make things so inconvenient for the programmers that the technique is abandoned. There are several ways that configuration interferes with programmers:

From these we can come up with some requirements:

Some other requirements come from extant ideas for configuration. XML brought us structured documents and this is perfect for configuration information as well. XML makes a lousy configuration medium because it is syntactically complex. Yaml has the advantage of being much simpler and just as powerful. Property files and command lines are initially easy but have no structure and run out of gas fast. Databases are good for structured data but are very complex to setup and use. File systems are nice and have a structured model but are perceived as heavyweight and difficult to manage. Let's go with yaml for a bit and see what we can use. Here's an example yaml file:

listenerUri: tcp://realty.net:4001
users:
    mary: { birthday: 1959-10-01, zip: 94001, pw: zowie1, active: true, interest: [ home, condo, apartment ] }
    jake: { birthday: 1967-01-19, zip: 78759, pw: flak33, active: false, interest: [ commercial ] }

Ok, we can see (or guess) the following:

(I'm taking a subset of the possible yaml capabilities, ignoring references and complex language dependent data types.)

(Note that, while I'm talking about yaml, that I'm using it as a programmer friendly model.)

The data types supported by yaml match etch capabilities as well. So, let's call these a requirement.

In the example above, we see that users is a map with two elements, mary and jake. Mary (and jake) is a map with 5 elements. We can think of maps (and lists and scalars) as nodes in a directed acyclic graph, with maps and lists containing more nodes within and scalars only having values. If I have my finger on the node users, I can reference mary's birthday by using the path "mary/birthday". I could also globally reference jake's password as the path "/users/jake/pw". The second of mary's interests could be referenced as the path "interest/1" with value condo. This naming scheme looks like a file system or network db, and so it is.

This allows us to treat subtrees of the configuration data generically, such as the subtrees "users/mary" and "users/jake" which are each "a user". By this abstraction we can write code which maps configuration data onto objects.

Some generic operations are suggested for nodes:

These operations work for all nodes. Given a node id, they return the appropriate property.

For nodes which are maps or lists, we need to be able to list the children:

Given a node id, lists the children of this node. A node id list is returned.

For nodes which are maps or lists, we need to be able to get a specific named (or indexed) child:

Given a node id and a path or index, gets the node id of the specified child node.

For nodes which are scalars, we need to be able to get the value:

The operation hasValue tests to see if the value is present, the get operations return the value as the requested data type if it is or can be converted to that type.

For convenience, the value getting operations include three extra methods: getMap, getList, and getSet. These take structural nodes and return them as best effort mappings into local equivalents of the raw underlying data. You lose the data conversion capabilities of the scalar access methods (getBoolean, etc.).

Example

Here is a code snippet to access a mary's birthday:

java.util.Date bd = service.getDate( service.getConfigPath( service.getRoot(), "users/mary/birthday" ) ) );

That's a bit of typing, eh? Generally you'd cache the value of root in a variable, and let's add a convenient operation to get a value given a node and a relative path without having to handle the node id ourselves:

Object root = service.getRoot();
...
java.util.Date bd = service.getDatePath( root, "users/mary/birthday" );

Complete Configuration IDL

Now, this interface I've defined, it includes only operations to access the configuration values, not change them. I've done it this way on purpose, so that we can quickly get started with a variety of sources and ignore the actual implementation. This interface could, in fact, be implemented in a variety of ways, including file system, network or relational db, property file, yaml file, xml file, command line, or environment variables. Where a particular service supports modification, it would perhaps require a specialized api for that. So, you'd define that api, mixin this basic access api, and that's your service. Clients (of the service) that only need to access the data would use just this basic access api.

I've not discussed operations relating to noticing updates (however accomplished). I'll catch up to that later. But they are in the access api. Here is a complete etch service idl.