package cz.cuni.mff.d3s.been.mq;
import java.io.Serializable;
import org.apache.commons.lang3.SerializationException;
import org.apache.commons.lang3.SerializationUtils;
import org.jeromq.ZMQ;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cz.cuni.mff.d3s.been.annotation.NotThreadSafe;
/**
* Sender for a queue in inter-process communication.
*
* The queue can send/receive only one type of an object, specified by the type
* parameter.
*
* Multiply senders can push messages to a receiver. We do not care who the
* receiver is. We just know that it will be received and taken care of.
*
* Implementation notes: Implemented using 0MQ PUSH-PULL model in 0MQ. This is
* the PUSH part.
*
* @see IMessageReceiver
* @author Martin Sixta
*/
@NotThreadSafe
final class InprocMessageSender<T extends Serializable> implements IMessageSender<T> {
/** Logging */
private final static Logger log = LoggerFactory.getLogger(InprocMessageSender.class);
/**
* ZMQ.Context to use for the connection.
*/
private final ZMQContext context;
/**
* ZMQ.Socket to communicate with.
*/
private ZMQ.Socket socket = null;
/**
* Connection string.
*/
private final String CONNECTION_STRING;
/**
*
* Creates new sender to the specified queue.
*
* @param context
* {@link org.jeromq.ZMQ.Context} to use
* @param queue
* name of the queue to connect to
*/
public InprocMessageSender(final ZMQContext context, final String queue) {
this.context = context;
CONNECTION_STRING = Messaging.createInprocConnection(queue);
}
/**
* Connects the sender to the queue.
*
* @throws cz.cuni.mff.d3s.been.mq.MessagingException
* when connection cannot be established.
*/
public void connect() throws MessagingException {
if (socket == null) {
socket = context.socket(ZMQ.PUSH);
boolean connected = socket.connect(CONNECTION_STRING);
if (!connected) {
String msg = String.format("Cannot connect to %s", CONNECTION_STRING);
throw new MessagingException(msg);
}
}
}
/**
* Disconnects the sender from the queue. Subsequent calls to
* {@link #send(java.io.Serializable)} will throw an exception.
*/
@Override
public void close() {
if (socket != null) {
socket.close();
socket = null;
}
}
/**
*
* Sends an object to a receiver(s).
*
* Must call {@link #connect()} before sending any objects.
*
* @param object
* Serializable object to send
* @throws cz.cuni.mff.d3s.been.mq.MessagingException
* when the object cannot be send
*/
@Override
public void send(final T object) throws MessagingException {
checkIsConnected();
try {
byte[] bytes = SerializationUtils.serialize(object);
boolean sent = socket.send(bytes);
if (!sent) {
String msg = String.format("Cannot send %s to %s", object, CONNECTION_STRING);
log.error(msg);
throw new MessagingException(msg);
}
} catch (SerializationException e) {
String msg = String.format("Cannot send %s to %s", object, CONNECTION_STRING);
log.error(msg, e);
throw new MessagingException(msg, e);
}
}
/**
* Checks if the sender is properly connected.
*
* @throws cz.cuni.mff.d3s.been.mq.MessagingException
* if the sender is not connected
*/
private void checkIsConnected() throws MessagingException {
if (socket == null) {
throw new MessagingException(String.format("Not connected to %s!", CONNECTION_STRING));
}
}
@Override
public String getConnection() {
return CONNECTION_STRING;
}
@Override
public void setLinger(int linger) {
socket.setLinger(linger);
}
}