/** 
 * 
 * Copyright 2004 Hiram Chirino
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 * 
 **/
package org.activemq;

import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

/**
 * @version $Revision: 1.1.1.1 $
 */
public class JmsRedeliveredTest extends TestCase {

    private Connection connection;
    
    protected void setUp() throws Exception {
        connection = createConnection();
    }

    /**
     * @see junit.framework.TestCase#tearDown()
     */
    protected void tearDown() throws Exception {
        if (connection != null) {
            connection.close();
            connection = null;
        }
    }
    
    protected Connection createConnection() throws JMSException{
        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost");
        return factory.createConnection();
    }

    /*
     * TODO: Currently fails. 
     */
    public void testQueueSessionCloseMarksMessageRedelivered() throws JMSException {

        connection.start();

        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
        Queue queue = session.createQueue("queue-"+getName());
        MessageProducer producer = createProducer(session, queue);
        producer.send(createTextMessage(session));

        // Consume the message...
        MessageConsumer consumer = session.createConsumer(queue);
        Message msg = consumer.receive(1000);
        assertNotNull(msg);        
        assertFalse("Message should not be redelivered.", msg.getJMSRedelivered());
        // Don't ack the message.
        
        // Reset the session.  This should cause the Unacked message to be redelivered.
        session.close();
        session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
                
        // Attempt to Consume the message...
        consumer = session.createConsumer(queue);
        msg = consumer.receive(2000);
        assertNotNull(msg);        
        assertTrue("Message should be redelivered.", msg.getJMSRedelivered());
        msg.acknowledge();
        
        session.close();
    }

    
    public void testQueueRecoverMarksMessageRedelivered() throws JMSException {

        connection.start();

        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
        Queue queue = session.createQueue("queue-"+getName());
        MessageProducer producer = createProducer(session, queue);
        producer.send(createTextMessage(session));

        // Consume the message...
        MessageConsumer consumer = session.createConsumer(queue);
        Message msg = consumer.receive(1000);
        assertNotNull(msg);        
        assertFalse("Message should not be redelivered.", msg.getJMSRedelivered());
        // Don't ack the message.
        
        // Reset the session.  This should cause the Unacked message to be redelivered.
        session.recover();
                
        // Attempt to Consume the message...
        msg = consumer.receive(2000);
        assertNotNull(msg);        
        assertTrue("Message should be redelivered.", msg.getJMSRedelivered());
        msg.acknowledge();
        
        session.close();
    }
    
    public void testQueueRollbackMarksMessageRedelivered() throws JMSException {
        connection.start();

        Session session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE);
        Queue queue = session.createQueue("queue-"+getName());
        MessageProducer producer = createProducer(session, queue);
        producer.send(createTextMessage(session));
        session.commit();
        
        // Get the message... Should not be redelivered.
        MessageConsumer consumer = session.createConsumer(queue);
        Message msg = consumer.receive(1000);
        assertNotNull(msg);        
        assertFalse("Message should not be redelivered.", msg.getJMSRedelivered());
        
        // Rollback.. should cause redelivery.
        session.rollback();
                        
        // Attempt to Consume the message...
        msg = consumer.receive(2000);
        assertNotNull(msg);        
        assertTrue("Message should be redelivered.", msg.getJMSRedelivered());
        
        
        session.commit();
        session.close();
    }
    
    public void testDurableTopicSessionCloseMarksMessageRedelivered() throws JMSException {

        connection.setClientID(getName());
        connection.start();

        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
        Topic topic = session.createTopic("topic-"+getName());
        MessageConsumer consumer = session.createDurableSubscriber(topic, "sub1");

        MessageProducer producer = createProducer(session, topic);
        producer.send(createTextMessage(session));

        // Consume the message...
        Message msg = consumer.receive(1000);
        assertNotNull(msg);        
        assertFalse("Message should not be redelivered.", msg.getJMSRedelivered());
        // Don't ack the message.
        
        // Reset the session.  This should cause the Unacked message to be redelivered.
        session.close();
        session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
                
        // Attempt to Consume the message...
        consumer = session.createDurableSubscriber(topic, "sub1");
        msg = consumer.receive(2000);
        assertNotNull(msg);        
        assertTrue("Message should be redelivered.", msg.getJMSRedelivered());
        msg.acknowledge();
        
        session.close();
    }
    
    public void testDurableTopicRecoverMarksMessageRedelivered() throws JMSException {

        connection.setClientID(getName());
        connection.start();

        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
        Topic topic = session.createTopic("topic-"+getName());
        MessageConsumer consumer = session.createDurableSubscriber(topic, "sub1");

        MessageProducer producer = createProducer(session, topic);
        producer.send(createTextMessage(session));

        // Consume the message...
        Message msg = consumer.receive(1000);
        assertNotNull(msg);        
        assertFalse("Message should not be redelivered.", msg.getJMSRedelivered());
        // Don't ack the message.
        
        // Reset the session.  This should cause the Unacked message to be redelivered.
        session.recover();
                
        // Attempt to Consume the message...
        msg = consumer.receive(2000);
        assertNotNull(msg);        
        assertTrue("Message should be redelivered.", msg.getJMSRedelivered());
        msg.acknowledge();
        
        session.close();
    }
    
    public void testDurableTopicRollbackMarksMessageRedelivered() throws JMSException {
        connection.setClientID(getName());
        connection.start();

        Session session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE);
        Topic topic = session.createTopic("topic-"+getName());
        MessageConsumer consumer = session.createDurableSubscriber(topic, "sub1");

        MessageProducer producer = createProducer(session, topic);
        producer.send(createTextMessage(session));
        session.commit();
        
        // Get the message... Should not be redelivered.
        Message msg = consumer.receive(1000);
        assertNotNull(msg);        
        assertFalse("Message should not be redelivered.", msg.getJMSRedelivered());
        
        // Rollback.. should cause redelivery.
        session.rollback();
                        
        // Attempt to Consume the message...
        msg = consumer.receive(2000);
        assertNotNull(msg);        
        assertTrue("Message should be redelivered.", msg.getJMSRedelivered());
        
        
        session.commit();
        session.close();
    }
     
    public void testTopicRecoverMarksMessageRedelivered() throws JMSException {

        connection.setClientID(getName());
        connection.start();

        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
        Topic topic = session.createTopic("topic-"+getName());
        MessageConsumer consumer = session.createConsumer(topic);

        MessageProducer producer = createProducer(session, topic);
        producer.send(createTextMessage(session));

        // Consume the message...
        Message msg = consumer.receive(1000);
        assertNotNull(msg);        
        assertFalse("Message should not be redelivered.", msg.getJMSRedelivered());
        // Don't ack the message.
        
        // Reset the session.  This should cause the Unacked message to be redelivered.
        session.recover();
                
        // Attempt to Consume the message...
        msg = consumer.receive(2000);
        assertNotNull(msg);        
        assertTrue("Message should be redelivered.", msg.getJMSRedelivered());
        msg.acknowledge();
        
        session.close();
    }
    
    public void testTopicRollbackMarksMessageRedelivered() throws JMSException {
        connection.setClientID(getName());
        connection.start();

        Session session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE);
        Topic topic = session.createTopic("topic-"+getName());
        MessageConsumer consumer = session.createConsumer(topic);

        MessageProducer producer = createProducer(session, topic);
        producer.send(createTextMessage(session));
        session.commit();
        
        // Get the message... Should not be redelivered.
        Message msg = consumer.receive(1000);
        assertNotNull(msg);        
        assertFalse("Message should not be redelivered.", msg.getJMSRedelivered());
        
        // Rollback.. should cause redelivery.
        session.rollback();
                        
        // Attempt to Consume the message...
        msg = consumer.receive(2000);
        assertNotNull(msg);        
        assertTrue("Message should be redelivered.", msg.getJMSRedelivered());        
        
        session.commit();
        session.close();
    }

    private TextMessage createTextMessage(Session session) throws JMSException {
        return session.createTextMessage("Hello");
    }
   
    private MessageProducer createProducer(Session session, Destination queue) throws JMSException {
         MessageProducer producer = session.createProducer(queue);
         producer.setDeliveryMode(getDeliveryMode());
         return producer;
    }
    
    protected int getDeliveryMode() {
        return DeliveryMode.PERSISTENT;
    }

    static final public class PersistentCase extends JmsRedeliveredTest {
        protected int getDeliveryMode() {
            return DeliveryMode.PERSISTENT;
        }
    }

    static final public class TransientCase extends JmsRedeliveredTest {
        protected int getDeliveryMode() {
            return DeliveryMode.NON_PERSISTENT;
        }
    }
    
    public static Test suite() { 
        TestSuite suite= new TestSuite(); 
        suite.addTestSuite(PersistentCase.class); 
        suite.addTestSuite(TransientCase.class); 
        return suite;
    }
}