reactor.net.zmq.tcp.ZeroMQ Maven / Gradle / Ivy
The newest version!
package reactor.net.zmq.tcp;
import com.gs.collections.api.list.MutableList;
import com.gs.collections.impl.block.function.checked.CheckedFunction0;
import com.gs.collections.impl.block.predicate.checked.CheckedPredicate;
import com.gs.collections.impl.list.mutable.FastList;
import com.gs.collections.impl.list.mutable.SynchronizedMutableList;
import com.gs.collections.impl.map.mutable.SynchronizedMutableMap;
import com.gs.collections.impl.map.mutable.UnifiedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import reactor.core.Environment;
import reactor.core.Reactor;
import reactor.core.composable.Deferred;
import reactor.core.composable.Promise;
import reactor.core.composable.spec.Promises;
import reactor.core.spec.Reactors;
import reactor.event.dispatch.Dispatcher;
import reactor.io.Buffer;
import reactor.io.encoding.Codec;
import reactor.io.encoding.StandardCodecs;
import reactor.net.NetChannel;
import reactor.net.tcp.TcpClient;
import reactor.net.tcp.TcpServer;
import reactor.net.tcp.spec.TcpClientSpec;
import reactor.net.tcp.spec.TcpServerSpec;
import reactor.net.zmq.ZeroMQClientSocketOptions;
import reactor.net.zmq.ZeroMQServerSocketOptions;
import reactor.support.NamedDaemonThreadFactory;
import reactor.util.Assert;
import java.lang.reflect.Field;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* @author Jon Brisbin
*/
public class ZeroMQ {
private static final SynchronizedMutableMap SOCKET_TYPES = SynchronizedMutableMap.of(UnifiedMap.newMap());
private final Logger log = LoggerFactory.getLogger(getClass());
private final MutableList> clients = SynchronizedMutableList.of(FastList.>newList());
private final MutableList> servers = SynchronizedMutableList.of(FastList.>newList());
private final ExecutorService threadPool = Executors.newCachedThreadPool(new NamedDaemonThreadFactory("zmq"));
private final Environment env;
private final Dispatcher dispatcher;
private final Reactor reactor;
private final ZContext zmqCtx;
@SuppressWarnings("unchecked")
private volatile Codec codec = (Codec) StandardCodecs.PASS_THROUGH_CODEC;
private volatile boolean shutdown = false;
public ZeroMQ(Environment env) {
this(env, env.getDefaultDispatcher());
}
public ZeroMQ(Environment env, String dispatcher) {
this(env, env.getDispatcher(dispatcher));
}
public ZeroMQ(Environment env, Dispatcher dispatcher) {
this.env = env;
this.dispatcher = dispatcher;
this.reactor = Reactors.reactor(env, dispatcher);
this.zmqCtx = new ZContext();
this.zmqCtx.setLinger(100);
}
public static String findSocketTypeName(final int socketType) {
return SOCKET_TYPES.getIfAbsentPut(socketType, new CheckedFunction0() {
@Override
public String safeValue() throws Exception {
for (Field f : ZMQ.class.getDeclaredFields()) {
if (int.class.isAssignableFrom(f.getType())) {
f.setAccessible(true);
try {
int val = f.getInt(null);
if (socketType == val) {
return f.getName();
}
} catch (IllegalAccessException e) {
}
}
}
return "";
}
});
}
public ZeroMQ codec(Codec codec) {
this.codec = codec;
return this;
}
public Promise> dealer(String addrs) {
return createClient(addrs, ZMQ.DEALER);
}
public Promise> push(String addrs) {
return createClient(addrs, ZMQ.PUSH);
}
public Promise> pull(String addrs) {
return createServer(addrs, ZMQ.PULL);
}
public Promise> request(String addrs) {
return createClient(addrs, ZMQ.REQ);
}
public Promise> reply(String addrs) {
return createServer(addrs, ZMQ.REP);
}
public Promise> router(String addrs) {
return createServer(addrs, ZMQ.ROUTER);
}
private Promise> createClient(String addrs, int socketType) {
Assert.isTrue(!shutdown, "This ZeroMQ instance has been shut down");
TcpClient client = new TcpClientSpec(ZeroMQTcpClient.class)
.env(env).dispatcher(dispatcher).codec(codec)
.options(new ZeroMQClientSocketOptions()
.context(zmqCtx)
.connectAddresses(addrs)
.socketType(socketType))
.get();
clients.add(client);
return client.open();
}
public Promise> createServer(String addrs, int socketType) {
Assert.isTrue(!shutdown, "This ZeroMQ instance has been shut down");
Deferred, Promise>> d = Promises.defer(env, dispatcher);
TcpServer server = new TcpServerSpec(ZeroMQTcpServer.class)
.env(env).dispatcher(dispatcher).codec(codec)
.options(new ZeroMQServerSocketOptions()
.context(zmqCtx)
.listenAddresses(addrs)
.socketType(socketType))
.consume(d)
.get();
servers.add(server);
server.start();
return d.compose();
}
public void shutdown() {
if (shutdown) {
return;
}
shutdown = true;
servers.removeIf(new CheckedPredicate>() {
@Override
public boolean safeAccept(TcpServer server) throws Exception {
Assert.isTrue(server.shutdown().await(60, TimeUnit.SECONDS), "Server " + server + " not properly shut down");
return true;
}
});
clients.removeIf(new CheckedPredicate>() {
@Override
public boolean safeAccept(TcpClient client) throws Exception {
Assert.isTrue(client.close().await(60, TimeUnit.SECONDS), "Client " + client + " not properly shut down");
return true;
}
});
// if (log.isDebugEnabled()) {
// log.debug("Destroying {} on {}", zmqCtx, this);
// }
// zmqCtx.destroy();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy