package org.krakenapps.logdb.impl;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;
import org.apache.felix.ipojo.annotations.Component;
import org.apache.felix.ipojo.annotations.Invalidate;
import org.apache.felix.ipojo.annotations.Provides;
import org.apache.felix.ipojo.annotations.Requires;
import org.apache.felix.ipojo.annotations.Validate;
import org.krakenapps.logdb.DataSource;
import org.krakenapps.logdb.DataSourceEventListener;
import org.krakenapps.logdb.DataSourceRegistry;
import org.krakenapps.logstorage.LogTableEventListener;
import org.krakenapps.logstorage.LogTableRegistry;
import org.krakenapps.logstorage.TableMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(name = "data-source-registry")
@Provides
public class DataSourceRegistryImpl implements DataSourceRegistry, LogTableEventListener {
private final Logger logger = LoggerFactory.getLogger(DataSourceRegistryImpl.class.getName());
@Requires
private LogTableRegistry tableRegistry;
private ConcurrentMap<DataSourceKey, DataSource> sources;
private CopyOnWriteArraySet<DataSourceEventListener> callbacks;
@Validate
public void start() {
sources = new ConcurrentHashMap<DataSourceKey, DataSource>();
callbacks = new CopyOnWriteArraySet<DataSourceEventListener>();
tableRegistry.addListener(this);
// add initial state
for (String name : tableRegistry.getTableNames()) {
int id = tableRegistry.getTableId(name);
TableMetadata metadata = tableRegistry.getTableMetadata(id);
update(new LogTableDataSource(name, toMap(metadata)));
}
}
private Map<String, String> toMap(TableMetadata metadata) {
Map<String, String> m = new HashMap<String, String>();
for (String key : metadata.keySet()) {
String value = metadata.get(key);
m.put(key.toString(), value == null ? null : value.toString());
}
return m;
}
@Invalidate
public void stop() {
if (tableRegistry != null)
tableRegistry.removeListener(this);
}
@Override
public Collection<DataSource> getAll() {
return Collections.unmodifiableCollection(sources.values());
}
@Override
public DataSource get(String nodeGuid, String name) {
return sources.get(new DataSourceKey(nodeGuid, name));
}
@Override
public void update(DataSource ds) {
sources.put(new DataSourceKey(ds), ds);
for (DataSourceEventListener callback : callbacks) {
try {
callback.onUpdate(ds);
} catch (Exception e) {
logger.warn("kraken logdb: data source callback should not throw any exception", e);
}
}
}
@Override
public void remove(DataSource ds) {
sources.remove(new DataSourceKey(ds));
for (DataSourceEventListener callback : callbacks) {
try {
callback.onRemove(ds);
} catch (Exception e) {
logger.warn("kraken logdb: data source callback should not throw any exception", e);
}
}
}
@Override
public void addListener(DataSourceEventListener listener) {
callbacks.add(listener);
}
@Override
public void removeListener(DataSourceEventListener listener) {
callbacks.remove(listener);
}
@Override
public void onCreate(String tableName, Map<String, String> tableMetadata) {
update(new LogTableDataSource(tableName, tableMetadata));
}
@Override
public void onDrop(String tableName) {
remove(new LogTableDataSource(tableName));
}
private static class LogTableDataSource implements DataSource {
private String tableName;
private Map<String, Object> metadata;
public LogTableDataSource(String tableName) {
this(tableName, null);
}
public LogTableDataSource(String tableName, Map<String, String> metadata) {
this.tableName = tableName;
this.metadata = new HashMap<String, Object>();
if (metadata != null)
this.metadata = new HashMap<String, Object>(metadata);
}
@Override
public String getNodeGuid() {
return "local";
}
@Override
public String getType() {
return "table";
}
@Override
public String getName() {
return tableName;
}
@Override
public Map<String, Object> getMetadata() {
return metadata;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((tableName == null) ? 0 : tableName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LogTableDataSource other = (LogTableDataSource) obj;
if (tableName == null) {
if (other.tableName != null)
return false;
} else if (!tableName.equals(other.tableName))
return false;
return true;
}
@Override
public String toString() {
return "table: " + tableName;
}
}
private static class DataSourceKey {
private String nodeGuid;
private String name;
public DataSourceKey(DataSource ds) {
this(ds.getNodeGuid(), ds.getName());
}
public DataSourceKey(String nodeGuid, String name) {
this.nodeGuid = nodeGuid;
this.name = name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((nodeGuid == null) ? 0 : nodeGuid.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DataSourceKey other = (DataSourceKey) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (nodeGuid == null) {
if (other.nodeGuid != null)
return false;
} else if (!nodeGuid.equals(other.nodeGuid))
return false;
return true;
}
}
}