import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.transaction.UserTransaction;

import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import java.text.*;

public final class mdbdemoTest extends HttpServlet
{
  private HashMap msgMap = new HashMap();
  private boolean testMDB = false;
  private static PrintWriter out = null;

  // Actually, 3*MAXMSGS msgs will be sent. See doTest() for details.
  private static final int MAXMSGS = 3;

	public void doGet(HttpServletRequest req, HttpServletResponse res)
    throws ServletException, IOException
	{
    doPost(req, res);
	}
	public void doPost(HttpServletRequest req, HttpServletResponse res)
    throws ServletException, IOException
	{
		res.setContentType("text/html");
		out = res.getWriter();

    // Are we asked to test MDBs also?
    String testmdb = req.getParameter ("testmdb");
    if (testmdb != null)
      testMDB = true;
    
    try
    {
      out.print ("<center><h2>TEST RESULTS</h2></center>");

      /* Do all the JNDI lookups first */
      lineBegin ("Looking up Queue connection factory...");
      QueueConnectionFactory qcf = (QueueConnectionFactory)
        jndiLookup ("java:comp/env/jms/QueueConnectionFactory");
      lineEnd ("Passed");

      lineBegin ("Looking up User Transaction...");
      UserTransaction ut = (UserTransaction)
        jndiLookup("java:comp/UserTransaction");
      lineEnd ("Passed");

      // Get connection metadata and print values obtained
      lineBegin ("Creating Queue connection...");
      QueueConnection qconn = qcf.createQueueConnection();
      lineEnd ("Passed");
      lineBegin ("Getting connection metadata...");
      ConnectionMetaData cmd = qconn.getMetaData();
      lineEnd ("Passed");

      lineBegin ("Looking up Queue 'demoQueue'...");
      Queue ourQ = (Queue) jndiLookup ("java:comp/env/jms/demoQueue");
      lineEnd ("Passed");

      QueueSession qsess = qconn.createQueueSession(false,
                                                   Session.AUTO_ACKNOWLEDGE);
      
      // Were we told to test mdbs also?
      qconn.start();

      doTest (qsess, ourQ, ut);
      qconn.close();
      out.print ("</table>");
    }
    catch (Exception e)
    {
      out.print ("<tr><td>** TEST FAILED **</td></table>");
      e.printStackTrace();
    }
    finally
    {
     out.print ("</table>");
    }
    
		
	}

  /***********************************************************************/

  private Object jndiLookup (String name)
    throws Exception
  {
    Object ret = null;

    Context ctx = new InitialContext();
    ret = ctx.lookup(name);
    ctx.close();

		if (ret == null)
			throw new Exception ("JNDI lookup failed for " + name);

    return ret;
  }


  /***********************************************************************/

  private void doTest (QueueSession sess,
                       Queue q,
                       UserTransaction ut)
    throws Exception
  {
    QueueSender snd = sess.createSender (q);

    TextMessage msg = null;

    // Drain old msgs from queue
    drainQueue (sess, q);

    /*
     * Send msgs to queue.
     */
    lineBegin ("Sending Messages...");
    for (int i = 0; i < MAXMSGS; i++)
    {
      msg = sess.createTextMessage();
      msg.setText ("TestMessage:" + i);

      // Send messages to MDB or to ourselves
      if (testMDB)
        msg.setStringProperty ("RECIPIENT", "MDB");
      else
        msg.setStringProperty ("RECIPIENT", "CLIENT");

      msg.setJMSReplyTo(q);
      snd.send (msg);

      msgMap.put (msg.getJMSMessageID(), new Long (msg.getJMSTimestamp()));
    }
    snd.close();

    lineEnd (MAXMSGS + " Messages Sent");

    if (testMDB)
      receiveFromMDB (sess, q);
    else
      receiveFromClient (sess, q);
  }

  /*
   * Receive any msgs sent to us
   */
  private void receiveFromClient (QueueSession sess, Queue q)
    throws Exception
  {
    // We will only receive msgs that have RECIPIENT set to 'CLIENT'
    QueueReceiver rcv = sess.createReceiver (q, "RECIPIENT = 'CLIENT'");
    
    /*
     * Now wait and dequeue msgs sent to us (by client or by MDB)
     * Note, first dequeue may take some time if MDB is processing it
     */
    int nrcvd = 0;
    long rcvtimes = 0;
    String msgid = null;
    
    lineBegin ("Receiving Messages...");
    TextMessage msg = (TextMessage) rcv.receive (10000);
    while (msg != null)
    {
      nrcvd++;
      String mtext = msg.getText();
      if (!mtext.equalsIgnoreCase ("TestMessage:" + (nrcvd - 1)))
        reportFailure ("Message Out of Order, expect " +
                       "TestMessage:" + (nrcvd - 1) + ", Got " +
                       mtext);
      String rcp = msg.getStringProperty ("RECIPIENT");
      if (!rcp.equalsIgnoreCase ("CLIENT"))
        reportFailure ("Received msg with Wrong Recipient " + rcp);

      msgid = msg.getJMSMessageID();
      msgMap.remove(msgid);

      // On to next msg
      msg = (TextMessage) rcv.receive (100);
    }

    if (nrcvd != MAXMSGS)
      reportFailure ("Received wrong number of msgs, Expect: " +
                     MAXMSGS + ", Got: " + nrcvd);

    lineEnd (nrcvd + " Messages Received");

    reportSuccess();
    rcv.close();
  }

  /*
   * Receive any msgs sent to us via the MDB
   */
  private void receiveFromMDB (QueueSession sess, Queue q)
    throws Exception
  {
    // We will only receive msgs that have RECIPIENT set to 'CLIENT'
    QueueReceiver rcv = sess.createReceiver (q, "RECIPIENT = 'CLIENT'");
    
    int nrcvd = 0;
    long trtimes = 0L;
    long tctimes = 0L;
    /*
     * First msg needs to come from MDB. Make take  a little while
     */
    lineBegin ("Receiving Messages...");
    for (Message msg = rcv.receive (30000); msg != null;
         msg = rcv.receive (30000))
    {
      nrcvd++;

      String rcp = msg.getStringProperty ("RECIPIENT");
      if (!rcp.equalsIgnoreCase ("CLIENT"))
        reportFailure ("Received msg with Wrong Recipient " + rcp);

      /* Verify if msg in message Map */
      String corrid = msg.getJMSCorrelationID();
      if (msgMap.containsKey(corrid))
      {
        msgMap.remove(corrid);
      }
      else
      {
        reportFailure ("** received unexpected message [" + corrid + "] **");
      }
    }

    if (nrcvd != MAXMSGS)
      reportFailure ("Received wrong number of msgs, Expect: " +
                     MAXMSGS + ", Got: " + nrcvd);

    lineEnd (nrcvd + " Messages Received");

    reportSuccess();
    rcv.close();
  }
  
  /*
   * Drain messages from queue
   */
  private int drainQueue (QueueSession sess,
                           Queue q)
    throws Exception
  {

    QueueReceiver rcv = sess.createReceiver (q);
    int nrcvd = 0;

    /*
     * First drain any old msgs from queue
     */
    lineBegin ("Drain Old Messsages...");
    for (Message msg = rcv.receive(1000);
         msg != null;
         msg = rcv.receive(1000))
      nrcvd++;

    lineEnd (nrcvd + " msgs drained");
    out.flush();
    rcv.close();
    
    return nrcvd;
  }

  private void reportFailure (String fail)
    throws Exception
  {
    lineEnd ("** FAILED **");
    lineBegin ("Queue send/receive Test Failed with...");
    lineEnd (fail);
    throw new Exception ("send/receive Test failed");
  }

  private void reportSuccess ()
    throws Exception
  {
    lineBegin ("Queue send/receive Test...");
    lineEnd ("Passed");
  }

  private void lineBegin (String str)
  {
    int spaces = 50 - str.length();
    out.print ("<p><pre>" + str);
    for (int i = 0; i < spaces; i++)
      out.print (" ");
  }

  private void lineEnd (String str)
  {
    out.print (str + "</pre></p>");
    out.flush();
  }
    
}
