package com.workshare.msnos.core;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ScheduledExecutorService;
import org.apache.http.client.HttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.workshare.msnos.core.Gateway.Listener;
import com.workshare.msnos.core.MsnosException.Code;
import com.workshare.msnos.core.protocols.ip.Endpoint;
import com.workshare.msnos.core.protocols.ip.HttpClientFactory;
import com.workshare.msnos.core.protocols.ip.MulticastSocketFactory;
import com.workshare.msnos.core.protocols.ip.http.HttpGateway;
import com.workshare.msnos.core.protocols.ip.udp.UDPGateway;
import com.workshare.msnos.core.protocols.ip.udp.UDPServer;
import com.workshare.msnos.core.protocols.ip.www.WWWGateway;
import com.workshare.msnos.core.serializers.WireJsonSerializer;
import com.workshare.msnos.soup.ShutdownHooks;
import com.workshare.msnos.soup.ShutdownHooks.Hook;
import com.workshare.msnos.soup.threading.ExecutorServices;
import com.workshare.msnos.soup.threading.Multicaster;
public class Gateways {
public static final String SYSP_GATE_WWW_DISABLE = "msnos.core.gateways.www.disable";
public static final String SYSP_GATE_UDP_DISABLE = "msnos.core.gateways.udp.disable";
public static final String SYSP_GATE_HTTP_DISABLE = "msnos.core.gateways.http.disable";
private static Logger log = LoggerFactory.getLogger(Gateways.class);
private static Set<Gateway> all = new CopyOnWriteArraySet<Gateway>();
public static final Set<Gateway> NONE = Collections.<Gateway> emptySet();
public static Set<Gateway> all() throws MsnosException {
if (all.size() == 0) {
addGateway(buildUDPGateway());
addGateway(buildWWWGateway());
addGateway(buildHttpGateway());
if (all.size() == 0)
throw new MsnosException("Unable to create at least one gateway", Code.UNRECOVERABLE_FAILURE);
addShutdownHook();
}
return all;
}
public static Set<Endpoint> allEndpoints() throws MsnosException {
HashSet<Endpoint> points = new HashSet<Endpoint>();
for (Gateway gate : all()) {
points.addAll(gate.endpoints().all());
}
return points;
}
public static Set<Endpoint> endpointsOf(Agent agent) throws MsnosException {
HashSet<Endpoint> points = new HashSet<Endpoint>();
for (Gateway gate : all()) {
points.addAll(gate.endpoints().of(agent));
}
return points;
}
public static Set<Endpoint> allPublicEndpoints() throws MsnosException {
HashSet<Endpoint> points = new HashSet<Endpoint>();
for (Gateway gate : all()) {
points.addAll(gate.endpoints().publics());
}
return points;
}
private static void addGateway(final Gateway gateway) {
if (gateway != null)
all.add(gateway);
}
private static void addShutdownHook() {
ShutdownHooks.addHook(new Hook() {
@Override
public void run() {
log.info("Closing gateways...");
for (Gateway gate : all)
close(gate);
log.info("done!");
}
private void close(Gateway gate) {
final String name = gate.getClass().getSimpleName();
try {
log.info("- closing gateway "+name+"...");
gate.close();
} catch (IOException ex) {
log.warn("Unexpected exception closing gateway "+name);
}
}
@Override
public String name() {
return "Gateway closer";
}
@Override
public int priority() {
return -1000;
}
});
}
private static Gateway buildHttpGateway() {
if (Boolean.getBoolean(SYSP_GATE_HTTP_DISABLE)) {
log.warn("HTTP Gateway disabled by system property!");
return null;
}
else
return new HttpGateway(newHttpClient());
}
private static UDPGateway buildUDPGateway() {
if (Boolean.getBoolean(SYSP_GATE_UDP_DISABLE)) {
log.warn("UDP Gateway disabled by system property!");
return null;
}
try {
final UDPServer server = new UDPServer();
final MulticastSocketFactory sockets = new MulticastSocketFactory();
return new UDPGateway(sockets, server, newMulticaster());
} catch (Throwable ex) {
log.error("Unable to create UDP gateway", ex);
return null;
}
}
private static WWWGateway buildWWWGateway() {
if (Boolean.getBoolean(SYSP_GATE_WWW_DISABLE)) {
log.warn("WWW Gateway disabled by system property!");
return null;
}
if (!System.getProperties().containsKey(WWWGateway.SYSP_ADDRESS)) {
log.warn("Missing configuration for WWW gateway, please add property "+WWWGateway.SYSP_ADDRESS);
return null;
}
try {
WWWGateway gate = new WWWGateway(newHttpClient(), newScheduler(), new WireJsonSerializer(), newMulticaster());
log.info("Succesfully connected to WWW gateway at {}", gate.root());
return gate;
} catch (Throwable ex) {
log.error("Unable to create WWW gateway", ex);
return null;
}
}
private static HttpClient newHttpClient() {
return HttpClientFactory.newHttpClient();
}
private static ScheduledExecutorService newScheduler() {
return ExecutorServices.newSingleThreadScheduledExecutor();
}
private static Multicaster<Listener, Message> newMulticaster() {
final Multicaster<Listener, Message> caster = new Multicaster<Gateway.Listener, Message>() {
@Override
protected void dispatch(Gateway.Listener listener, Message message) {
listener.onMessage(message);
}
};
return caster;
}
static void reset() {
log.warn("Somebody reset the gateways!");
all = new CopyOnWriteArraySet<Gateway>();
}
}