Skip to main content

Custom ConfigStores

The ConfigStore API has been written to allow easy development of custom configuration storage classes. The example below shows a starting point for an implementation based on polling a relational database. The source can be found here: SqlStore.

Completing it is left as an exercise:

Example Store Class
public class SqlStore extends ConfigStore {

private final String jdbcUrl;
private final String tableName, nameColumn, valueColumn;
private final Timer watcher;
private final ConcurrentHashMap cache = new ConcurrentHashMap();

protected SqlStore(ConfigStore.Builder builder) {
super(builder);
this.jdbcUrl = builder.jdbcUrl;
this.tableName = builder.tableName;
this.nameColumn = builder.nameColumn;
this.valueColumn = builder.valueColumn;

int pollInterval = builder.pollInterval;

TimerTask timerTask = new TimerTask() {
@Override
public void run() {
SqlStore.this.poll();
}
};

this.watcher = new Timer("MyTimer");
watcher.scheduleAtFixedRate(timerTask, 0, pollInterval * 1000);
}

synchronized void poll() {
// Loop through all our entries and find the latest values.
for (Map.Entry e : cache.entrySet()) {
String name = e.getKey();
String cacheContents = e.getValue();
String newContents = getDatabaseValue(name);

// Change detected!
if (! cacheContents.equals(newContents))
update(name, newContents);
}
}

// Reads the value from the database.
protected String getDatabaseValue(String name) {
// Implement me!
return null;
}

@Override /* ConfigStore */
public boolean exists(String name) {
// Implement me!
return false;
}

@Override /* ConfigStore */
public synchronized String read(String name) {
String contents = cache.get(name);
if (contents == null) {
contents = getDatabaseValue(name);
update(name, contents);
}
return contents;
}

@Override /* ConfigStore */
public synchronized String write(String name, String expectedContents, String newContents) {

// This is a no-op.
if (StringUtils.eq(expectedContents, newContents))
return null;

String currentContents = read(name);

if (expectedContents != null && StringUtils.ne(currentContents, expectedContents))
return currentContents;

update(name, newContents);

// Success!
return null;
}

@Override /* ConfigStore */
public synchronized SqlStore update(String name, String newContents) {
cache.put(name, newContents);
super.update(name, newContents); // Trigger any listeners.
return this;
}

@Override /* Closeable */
public synchronized void close() {
if (watcher != null)
watcher.cancel();
}
}