package cgl.iotcloud.core.sensorsite;
import cgl.iotcloud.core.Configuration;
import cgl.iotcloud.core.Utils;
import cgl.iotcloud.core.sensorsite.thrift.TSensorSiteService;
import cgl.iotcloud.core.transport.Transport;
import com.google.common.eventbus.EventBus;
import org.apache.thrift.server.THsHaServer;
import org.apache.thrift.transport.TNonblockingServerSocket;
import org.apache.thrift.transport.TNonblockingServerTransport;
import org.apache.thrift.transport.TTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Constructor;
import java.net.InetSocketAddress;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Executors;
public class SensorSite {
private static Logger LOG = LoggerFactory.getLogger(SensorSite.class);
private SiteContext siteContext;
private SiteSensorDeployer sensorDeployer;
private THsHaServer server;
private Map conf;
private EventBus sensorEventBus = new EventBus();
private EventBus masterEventBus = new EventBus();
private MasterUpdater masterUpdater;
public void start() {
// read the configuration file
conf = Utils.readConfig();
String siteId = Configuration.getSiteId(conf);
if (siteId == null) {
siteId = UUID.randomUUID().toString().replaceAll("-", "");
}
// create the site context
siteContext = new SiteContext(siteId, conf);
// read the available transports and register them
Map transports = Configuration.getTransports(conf);
if (transports == null) {
String msg = "At least one transport must be configured";
LOG.error(msg);
throw new RuntimeException(msg);
}
// load the transport files and add them to context
for (Object e : transports.entrySet()) {
if (e instanceof Map.Entry) {
Object tName = ((Map.Entry) e).getKey();
Object tConf = ((Map.Entry) e).getValue();
if (!(tName instanceof String)) {
String msg = "The transport name should be an string";
LOG.error(msg);
throw new RuntimeException(msg);
}
if (!(tConf instanceof Map)) {
String msg = "The transport configurations should be in a map";
LOG.error(msg);
throw new RuntimeException(msg);
}
Transport t = loadTransport((Map) tConf);
// configure the transport, this doesn't start the transport
t.configure(siteId, (Map) tConf);
siteContext.addTransport((String) tName, t);
LOG.info("Registered transport {}", tName);
}
}
// start the transports for sensor messages
for (Transport t : siteContext.getTransports().values()) {
t.start();
}
sensorDeployer = new SiteSensorDeployer(conf, siteContext, masterEventBus);
sensorEventBus.register(sensorDeployer);
masterUpdater = new MasterUpdater(siteContext);
masterEventBus.register(masterUpdater);
Thread t = new Thread(new Runnable() {
@Override
public void run() {
// now start the server to listen for the master commands
try {
String host = Configuration.getSensorSiteHost(conf);
int port = Configuration.getSensorSitePort(conf);
InetSocketAddress addres = new InetSocketAddress(host, port);
TNonblockingServerTransport serverTransport = new TNonblockingServerSocket(addres);
server = new THsHaServer(
new THsHaServer.Args(serverTransport).processor(
new TSensorSiteService.Processor <SensorSiteService>(
new SensorSiteService(siteContext, sensorEventBus))).executorService(
Executors.newFixedThreadPool(Configuration.getSensorSiteThreads(conf))));
LOG.info("Starting the SensorSite server on host: {} and port: {}", host, port);
server.serve();
} catch (TTransportException e) {
String msg = "Error starting the Thrift server";
LOG.error(msg);
throw new RuntimeException(msg);
}
}
});
t.start();
MasterConnection masterConnection = new MasterConnection(conf, siteContext);
masterConnection.start();
}
public void stop() {
LOG.info("Stopping the sensor site {}", siteContext.getSiteId());
// we first un register from the master
masterUpdater.unRegisterSite();
// stop the transports
for (Map.Entry<String, Transport> e : siteContext.getTransports().entrySet()) {
LOG.info("Stopping transport {}", e.getKey());
e.getValue().stop();
}
// stop the server
server.stop();
LOG.info("Sensor site {} stopped ", siteContext.getSiteId());
}
public static void main(String[] args) {
final SensorSite site = new SensorSite();
site.start();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
site.stop();
}
});
}
private static Transport loadTransport(Map transportConf) {
String className = Configuration.getTransportClass(transportConf);
try {
Class<?> clazz = Class.forName(className);
Class<? extends Transport> runClass = clazz.asSubclass(Transport.class);
// Avoid Class.newInstance, for it is evil.
Constructor<? extends Transport> ctor = runClass.getConstructor();
return ctor.newInstance();
} catch (ClassNotFoundException x) {
LOG.error("Transport class cannot be found {}", className, x);
throw new RuntimeException("Transport class cannot be found " + className, x);
} catch (InstantiationException x) {
LOG.error("Transport class cannot be instantiated {}", className, x);
throw new RuntimeException("Transport class cannot be instantiated " + className, x);
} catch (Exception e) {
LOG.error("Error loading the class {}", className, e);
throw new RuntimeException("Error loading the class " + className, e);
}
}
}