package ch.epfl.gsn.networking.zeromq; import java.io.ByteArrayInputStream; import java.net.URI; import java.net.URISyntaxException; import org.zeromq.ZContext; import org.slf4j.LoggerFactory; import org.slf4j.Logger; import org.zeromq.ZMQ; import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.io.Input; import ch.epfl.gsn.Main; import ch.epfl.gsn.beans.AddressBean; import ch.epfl.gsn.beans.DataField; import ch.epfl.gsn.beans.StreamElement; import ch.epfl.gsn.delivery.StreamElement4Rest; import ch.epfl.gsn.wrappers.AbstractWrapper; public class ZeroMQWrapperAsync extends AbstractWrapper { private transient Logger logger = LoggerFactory.getLogger( this.getClass() ); private DataField[] structure; private String remoteContactPoint_DATA; private String remoteContactPoint_META; private String vsensor; private Kryo kryo = new Kryo(); private boolean isLocal = false; ZMQ.Socket requester = null; @Override public DataField[] getOutputFormat() { if (structure == null){ if (requester.send(vsensor)){ byte[] rec = requester.recv(); if (rec != null){ structure = kryo.readObjectOrNull(new Input(new ByteArrayInputStream(rec)),DataField[].class); if (structure != null) requester.close(); return structure; } } } return structure; } @Override public boolean initialize() { kryo.register(StreamElement4Rest.class); kryo.register(DataField[].class); AddressBean addressBean = getActiveAddressBean(); String address = addressBean.getPredicateValue ( "address" ).toLowerCase(); int dport = addressBean.getPredicateValueAsInt("data_port",Main.getContainerConfig().getZMQProxyPort()); int mport = addressBean.getPredicateValueAsInt("meta_port", Main.getContainerConfig().getZMQMetaPort()); vsensor = addressBean.getPredicateValue ( "vsensor" ).toLowerCase(); if ( address == null || address.trim().length() == 0 ) throw new RuntimeException( "The >address< parameter is missing from the ZeroMQWrapper wrapper." ); try { isLocal = new URI(address).getScheme().equals("inproc"); } catch (URISyntaxException e) { throw new IllegalArgumentException(e); } if (! isLocal ){ remoteContactPoint_DATA = address.trim() + ":" + dport; remoteContactPoint_META = address.trim() + ":" + mport; }else{ if(!Main.getContainerConfig().isZMQEnabled()){ throw new IllegalArgumentException("The \"inproc\" communication can only be used if the current GSN server has zeromq enabled. Please add <zmq-enable>true</zmq-enable> to conf/ch.epfl.gsn.xml."); } remoteContactPoint_DATA = address.trim(); remoteContactPoint_META = "tcp://127.0.0.1:" + Main.getContainerConfig().getZMQMetaPort(); } ZContext ctx = Main.getZmqContext(); requester = ctx.createSocket(ZMQ.REQ); requester.setReceiveTimeOut(1000); requester.setSendTimeOut(1000); requester.connect((remoteContactPoint_META).trim()); if (requester.send(vsensor)){ byte[] rec = requester.recv(); if (rec != null){ structure = kryo.readObjectOrNull(new Input(new ByteArrayInputStream(rec)),DataField[].class); if (structure != null) requester.close(); } } return true; } @Override public void dispose() { } @Override public String getWrapperName() { return "ZeroMQ wrapper"; } @Override public void run(){ ZContext context = Main.getZmqContext(); ZMQ.Socket subscriber = context.createSocket(ZMQ.SUB); boolean connected = subscriber.base().connect(remoteContactPoint_DATA); subscriber.setReceiveTimeOut(1000); subscriber.setRcvHWM(0); // no limit subscriber.subscribe((vsensor+":").getBytes()); while (isActive()) { try{ byte[] rec = subscriber.recv(); if (rec != null){ ByteArrayInputStream bais = new ByteArrayInputStream(rec); bais.skip(vsensor.getBytes().length + 2); StreamElement se = kryo.readObjectOrNull(new Input(bais),StreamElement.class); postStreamElement(se); }else{ if (isLocal && !connected){ subscriber.disconnect(remoteContactPoint_DATA); connected = subscriber.base().connect(remoteContactPoint_DATA); } subscriber.subscribe((vsensor+":").getBytes()); } }catch (Exception e) { logger.error("ZMQ wrapper error: ",e); } } subscriber.unsubscribe((vsensor+":").getBytes()); try { Thread.sleep(4000); } catch (InterruptedException e) {} subscriber.close(); } @Override public boolean isTimeStampUnique(){ return false; } }