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 ZeroMQWrapperSync extends AbstractWrapper { private transient Logger logger = LoggerFactory.getLogger( this.getClass() ); private DataField[] structure; private String remoteContactPoint_META; private String vsensor; private Kryo kryo = new Kryo(); private boolean isLocal = false; private ZContext ctx; private ZMQ.Socket requester = null; private ZMQ.Socket receiver = null; private int lport = 0; private String laddress; @Override public DataField[] getOutputFormat() { if (structure == null){ requester = ctx.createSocket(ZMQ.REQ); requester.setReceiveTimeOut(1000); requester.setSendTimeOut(1000); requester.setLinger(0); requester.connect(remoteContactPoint_META); if (requester.send(vsensor + "?tcp://" + laddress + ":" + lport)){ byte[] rec = requester.recv(); if (rec != null){ structure = kryo.readObjectOrNull(new Input(new ByteArrayInputStream(rec)),DataField[].class); if (structure != null) requester.close(); return structure; } } requester.close(); } return structure; } @Override public boolean initialize() { kryo.register(StreamElement4Rest.class); kryo.register(DataField[].class); AddressBean addressBean = getActiveAddressBean(); String address = addressBean.getPredicateValue ( "address" ).toLowerCase(); int mport = addressBean.getPredicateValueAsInt("meta_port", Main.getContainerConfig().getZMQMetaPort()); String _lport = addressBean.getPredicateValue("local_port"); laddress = addressBean.getPredicateValue("local_address"); vsensor = addressBean.getPredicateValue ( "vsensor" ).toLowerCase(); if ( address == null || address.trim().length() == 0 ) throw new RuntimeException( "The >address< parameter is missing from the ZeroMQ wrapper." ); if ( laddress == null || laddress.trim().length() == 0 ) throw new RuntimeException( "The >local_address< parameter is missing from the ZeroMQ wrapper." ); if (_lport != null){ lport = Integer.parseInt(_lport); if ( lport < 0 || lport > 65535 ) throw new RuntimeException( "The >local_port< parameter must be a valid port number." ); } try { isLocal = new URI(address).getScheme().equals("inproc"); } catch (URISyntaxException e) { throw new IllegalArgumentException(e); } if (! isLocal ){ 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_META = "tcp://127.0.0.1:" + Main.getContainerConfig().getZMQMetaPort(); } remoteContactPoint_META = remoteContactPoint_META.trim(); ctx = Main.getZmqContext(); receiver = ctx.createSocket(ZMQ.REP); if (lport == 0){ lport = receiver.bindToRandomPort("tcp://*", 50000, 60000); } else { receiver.bind("tcp://*:"+lport); } requester = ctx.createSocket(ZMQ.REQ); requester.setReceiveTimeOut(1000); requester.setSendTimeOut(1000); requester.setLinger(0); requester.connect(remoteContactPoint_META); if (requester.send(vsensor + "?tcp://" + laddress + ":" + lport)){ byte[] rec = requester.recv(); if (rec != null){ structure = kryo.readObjectOrNull(new Input(new ByteArrayInputStream(rec)),DataField[].class); } } requester.close(); return true; } @Override public void dispose() { } @Override public String getWrapperName() { return "ZeroMQ wrapper"; } @Override public void run(){ while (isActive()) { try{ byte[] rec = receiver.recv(); if (rec != null){ ByteArrayInputStream bais = new ByteArrayInputStream(rec); StreamElement se = kryo.readObjectOrNull(new Input(bais),StreamElement.class); boolean success = postStreamElement(se); receiver.send(success ? new byte[]{(byte)0} : new byte[]{(byte)1}); } }catch (Exception e) { logger.error("ZMQ wrapper error: ",e); } } receiver.close(); } @Override public boolean isTimeStampUnique(){ return false; } }