package cz.cuni.mff.d3s.been.socketworks.twoway;
import org.jeromq.ZMQ;
import org.jeromq.ZMQ.Socket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cz.cuni.mff.d3s.been.annotation.NotThreadSafe;
import cz.cuni.mff.d3s.been.mq.Context;
import cz.cuni.mff.d3s.been.mq.MessagingException;
import cz.cuni.mff.d3s.been.mq.ZMQContext;
/**
* Sends requests of tasks to its Host Runtime.
*
* The Requestor provides REQ-REP semantics for tasks. Requests are handled by
* the corresponding Host Runtime. The methods block until the request is
* handled. The blocking time is unbounded for some requests (use timeout if you
* don't want to block for arbitrary long time).
*
* Calls are not thread safe. Create a requester for each thread (and inside the
* thread) which might want to issue request.
*
*
* After you are done, {@link #close()} must be called. Otherwise the process
* will not terminate.
*
*
* @author Martin Sixta
*/
@NotThreadSafe
public class Requestor {
/** logging */
private static final Logger log = LoggerFactory.getLogger(Requestor.class);
/** 0MQ context of this requestor */
private final ZMQContext zctx;
/** The socket used to communicate with a Host Runtime. */
private final Socket socket;
/**
* Creates a new Requestor. Each thread must create its own Requestor, the
* class is not thread safe. Also the object should be created in the thread
* that wants to use it.
*/
private Requestor(String address, ZMQContext zctx, Socket socket) {
this.zctx = zctx;
this.socket = socket;
socket.setLinger(0);
socket.connect(address);
}
/**
* Create a two-way messaging requestor
*
* @param address Address requests will be sent to
*
* @return The requestor
*
* @throws MessagingException When requestor creation fails (e.g. I/O error on connection)
*/
public static Requestor create(String address) throws MessagingException {
final ZMQContext zctx = Context.getReference();
return new Requestor(address, zctx, zctx.socket(ZMQ.REQ));
}
/**
* Sends an arbitrary request, waits for reply. The call will block until the
* request is handled by the Host Runtime.
*
* @param request
* The request
*
* @return Reply for the request
*/
public String request(String request) {
socket.send(request);
log.trace("Sent {}", request);
final String replyString = socket.recvStr();
log.trace("Received {}", replyString);
return replyString;
}
/**
* Closes the requestor. No further request will be handled by the object.
*
* Must be called to release associated resources. Failing to do so will hand
* the process on exit.
*
* @throws MessagingException On I/O error when closing the requestor
*/
public void close() throws MessagingException {
socket.close();
zctx.term();
}
}