package org.skyscreamer.nevado.jms;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.skyscreamer.nevado.jms.message.NevadoMessage;
import javax.jms.Destination;
import javax.jms.JMSException;
import java.util.*;
/**
* MessageHolder to allow sessions to hold onto messages in CLIENT_ACKNOWLEDGE mode
*
* @author Carter Page <carter@skyscreamer.org>
*/
public class MessageHolder {
private final Log _log = LogFactory.getLog(getClass());
private final NevadoSession _session;
private final Map<Destination, List<NevadoMessage>> _messageHolder
= new HashMap<Destination, List<NevadoMessage>>();
private final Map<Destination, Integer> _messageIndex = new HashMap<Destination, Integer>();
public MessageHolder(NevadoSession session) {
_session = session;
}
public void add(Destination destination, NevadoMessage msg)
{
if (!_messageHolder.containsKey(destination))
{
_messageHolder.put(destination, new ArrayList<NevadoMessage>());
}
List<NevadoMessage> messageList = _messageHolder.get(destination);
int index = _messageIndex.containsKey(destination) ? _messageIndex.get(destination) : 0;
if (index < messageList.size())
{
throw new IllegalStateException("Cannot add message while in replay mode");
}
messageList.add(msg);
_messageIndex.put(destination, index + 1);
}
public NevadoMessage getNextMessage(Destination destination) {
NevadoMessage message = null;
if (_messageHolder.containsKey(destination))
{
List<NevadoMessage> messageList = _messageHolder.get(destination);
int index = _messageIndex.get(destination);
if (index < messageList.size())
{
message = messageList.get(index);
_messageIndex.put(destination, index + 1);
}
}
return message;
}
public void acknowledgeConsumedMessages() throws JMSException
{
// Separate the wheat from the chaff
List<NevadoMessage> consumedMessages = new ArrayList<NevadoMessage>();
List<NevadoMessage> unconsumedMessages = new ArrayList<NevadoMessage>();
for(Destination destination : _messageHolder.keySet())
{
for(NevadoMessage msg : getConsumedMessages(destination))
{
consumedMessages.add(msg);
}
for(NevadoMessage msg : getUnconsumedMessages(destination))
{
unconsumedMessages.add(msg);
}
}
// Delete consumed messages, reset the rest
_session.deleteMessage(consumedMessages.toArray(new NevadoMessage[0]));
for(NevadoMessage msg : consumedMessages)
{
msg.setAcknowledged(true);
}
_session.resetMessage(unconsumedMessages.toArray(new NevadoMessage[0]));
// Re-initialize state
_messageHolder.clear();
_messageIndex.clear();
}
public void close() throws JMSException {
reset();
for(Destination destination : _messageHolder.keySet())
{
_session.resetMessage(getUnconsumedMessages(destination).toArray(new NevadoMessage[0]));
}
}
public List<NevadoMessage> getConsumedMessages()
{
List<NevadoMessage> consumedMessages = new ArrayList<NevadoMessage>();
for(Destination destination : _messageHolder.keySet())
{
for(NevadoMessage msg : getConsumedMessages(destination))
{
consumedMessages.add(msg);
}
}
return consumedMessages;
}
private List<NevadoMessage> getConsumedMessages(Destination destination)
{
if (_messageHolder.containsKey(destination))
{
List<NevadoMessage> messageList = _messageHolder.get(destination);
int index = _messageIndex.get(destination);
return messageList.subList(0, index);
}
else
{
return Collections.emptyList();
}
}
private List<NevadoMessage> getUnconsumedMessages(Destination destination)
{
if (_messageHolder.containsKey(destination))
{
List<NevadoMessage> messageList = _messageHolder.get(destination);
int index = _messageIndex.get(destination);
return messageList.subList(index, messageList.size());
}
else
{
return Collections.emptyList();
}
}
public void reset()
{
for(Destination destination : _messageIndex.keySet())
{
_messageIndex.put(destination, 0);
}
}
}