package com.rubiconproject.oss.kv.backends;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import com.rubiconproject.oss.kv.KeyValueStore;
import com.rubiconproject.oss.kv.KeyValueStoreUnavailable;
import com.rubiconproject.oss.kv.annotations.Configurable;
public abstract class AbstractConnectionFactory implements ConnectionFactory {
private Map<String, KeyValueStore> backends = new HashMap<String, KeyValueStore>();
public KeyValueStore getStore(Map defaultProperties, String uri) throws IOException,
KeyValueStoreUnavailable {
KeyValueStore store = backends.get(uri);
if (store == null) {
synchronized (this) {
// check again...
store = backends.get(uri);
if (store == null) {
// yes i realize this is an anti-pattern. if we create an
// extra connection here and there nobody is going to care.
try {
store = createStoreConnection(uri);
// set the defaults from the provided map
if (defaultProperties != null)
configureStore(store, defaultProperties);
// set values from the given url
Map<String, String> props = getStoreProperties(uri);
if (props != null)
configureStore(store, props);
store.start();
backends.put(uri, store);
} catch (IllegalArgumentException e) {
throw new KeyValueStoreUnavailable(e);
} catch (IllegalAccessException e) {
throw new KeyValueStoreUnavailable(e);
} catch (InvocationTargetException e) {
throw new KeyValueStoreUnavailable(e);
}
}
}
}
return store;
}
protected void configureStore(KeyValueStore store,
Map<String, String> configs) throws IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
Method[] methods = store.getClass().getMethods();
for (Method method : methods) {
Configurable annotation = method.getAnnotation(Configurable.class);
if (annotation != null) {
String name = annotation.name();
String value = configs.get(name);
if (value != null) {
Object obj = annotation.accepts().fromString(value);
setFieldValue(store, method, obj);
}
}
}
}
private void setFieldValue(KeyValueStore store, Method method, Object value)
throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
method.invoke(store, value);
}
public abstract Map<String, String> getStoreProperties(String uri)
throws IllegalArgumentException;
public abstract KeyValueStore createStoreConnection(String uri)
throws IOException, KeyValueStoreUnavailable;
}