/*
* Copyright 2015 Edward Capriolo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.teknek.nibiru;
import io.teknek.nibiru.client.InternodeClient;
import io.teknek.nibiru.cluster.ClusterMembership;
import io.teknek.nibiru.coordinator.Coordinator;
import io.teknek.nibiru.engine.atom.AtomValue;
import io.teknek.nibiru.personality.ColumnFamilyPersonality;
import io.teknek.nibiru.plugins.AbstractPlugin;
import io.teknek.nibiru.transport.HttpJsonTransport;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.google.common.annotations.VisibleForTesting;
public class Server {
private final ConcurrentMap<String,Keyspace> keyspaces;
private final Configuration configuration;
private final MetaDataManager metaDataManager;
private final HttpJsonTransport transport;
private final Coordinator coordinator;
private final ServerId serverId;
private final ClusterMembership clusterMembership;
private final Map<String,AbstractPlugin> plugins;
public Server(Configuration configuration){
this.configuration = configuration;
keyspaces = new ConcurrentHashMap<String,Keyspace>();
metaDataManager = new MetaDataManager(configuration, this);
serverId = new ServerId(configuration);
clusterMembership = ClusterMembership.createFrom(configuration, serverId);
coordinator = new Coordinator(this);
transport = new HttpJsonTransport(configuration, coordinator);
plugins = new ConcurrentHashMap<String,AbstractPlugin>();
}
public void init(){
serverId.init();
metaDataManager.init();
clusterMembership.init();
coordinator.init();
transport.init();
initPlugins();
}
private void initPlugins(){
for (String plugin : configuration.getPlugins()){
try {
Constructor<?> c = Class.forName(plugin).getConstructor(Server.class);
AbstractPlugin p = (AbstractPlugin) c.newInstance(this);
plugins.put(p.getName(), p);
} catch (NoSuchMethodException | SecurityException | ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
for (Map.Entry<String, AbstractPlugin> pluginEntry: plugins.entrySet()){
pluginEntry.getValue().init();
}
}
public void shutdown() {
transport.shutdown();
coordinator.shutdown();
clusterMembership.shutdown();
for (Map.Entry<String, Keyspace> entry : keyspaces.entrySet()){
for (Map.Entry<String, Store> columnFamilyEntry : entry.getValue().getStores().entrySet()){
try {
columnFamilyEntry.getValue().shutdown();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
for (Map.Entry<String, AbstractPlugin> pluginEntry: plugins.entrySet()){
pluginEntry.getValue().shutdown();
}
}
public void put(String keyspace, String columnFamily, String rowkey, String column, String value, long time){
Keyspace ks = keyspaces.get(keyspace);
Store cf = ks.getStores().get(columnFamily);
if (cf instanceof ColumnFamilyPersonality){
((ColumnFamilyPersonality) cf).put(rowkey, column, value, time, 0L);
} else {
throw new RuntimeException("Does not support this personality");
}
}
public void put(String keyspace, String columnFamily, String rowkey, String column, String value, long time, long ttl){
Keyspace ks = keyspaces.get(keyspace);
Store cf = ks.getStores().get(columnFamily);
if (cf instanceof ColumnFamilyPersonality){
((ColumnFamilyPersonality) cf).put(rowkey, column, value, time);
} else {
throw new RuntimeException("Does not support this personality");
}
}
public AtomValue get(String keyspace, String columnFamily, String rowkey, String column){
Keyspace ks = keyspaces.get(keyspace);
if (ks == null){
throw new RuntimeException(keyspace + " is not found");
}
Store cf = ks.getStores().get(columnFamily);
if (cf instanceof ColumnFamilyPersonality){
return ((ColumnFamilyPersonality) cf).get(rowkey, column);
} else {
throw new RuntimeException("Does not support this personality");
}
}
public void delete(String keyspace, String columnFamily, String rowkey, String column, long time){
Keyspace ks = keyspaces.get(keyspace);
Store cf = ks.getStores().get(columnFamily);
if (cf instanceof ColumnFamilyPersonality){
((ColumnFamilyPersonality) cf).delete(rowkey, column, time);
} else {
throw new RuntimeException("Does not support this personality");
}
}
@VisibleForTesting
public void join(String keyspace, String sponsorHost, String wantedToken){
InternodeClient internodeClient = new InternodeClient(sponsorHost, configuration.getTransportPort(), 10000, 10000);
internodeClient.join(keyspace, sponsorHost, serverId, wantedToken, configuration.getTransportHost());
}
public ConcurrentMap<String, Keyspace> getKeyspaces() {
return keyspaces;
}
public Configuration getConfiguration() {
return configuration;
}
public MetaDataManager getMetaDataManager() {
return metaDataManager;
}
public ServerId getServerId() {
return serverId;
}
public ClusterMembership getClusterMembership() {
return clusterMembership;
}
public Coordinator getCoordinator() {
return coordinator;
}
public Map<String, AbstractPlugin> getPlugins() {
return plugins;
}
public static void main(String [] args) throws FileNotFoundException {
String configPath = args[0];
File f = new File(configPath);
java.beans.XMLDecoder d = new java.beans.XMLDecoder(new FileInputStream(f));
Configuration config = (Configuration) d.readObject();
d.close();
Server s = new Server(config);
s.init();
}
}