package examples.xml.jms;

import java.io.*;
import java.util.*;
import javax.jts.*;
import javax.naming.*;
import javax.jms.*;
import org.w3c.dom.*;
import com.sun.xml.tree.XmlDocumentBuilder;
import com.sun.xml.parser.Parser;
import com.sun.xml.parser.Resolver;
import org.xml.sax.InputSource;
import com.sun.xml.tree.ElementNode;
import com.sun.xml.tree.XmlDocument;

/**
 * This example shows how to pass XML data within a JMS message. The 
 * classes in this package make up a simple workflow system. This class 
 * is used to approve or deny messages created from the 
 * <tt>Client</tt> class. Message received from the JMS queue are in the 
 * form of XML data. The XML is parsed using a SAX compliant parser and 
 * the contents are displayed in the console. This class updates attributes 
 * of the XML data based upon whether or not the message has been approved and returns 
 * the message to the queue, where it will be received by the <tt>Client</tt> class. 
 *
 * @author Copyright (c) 2000 by BEA Systems, Inc. All Rights Reserved.
 */
public class AdminClient
  implements MessageListener
{
  public final static String JNDI_FACTORY="weblogic.jndi.WLInitialContextFactory";
  public final static String JMS_FACTORY="javax.jms.QueueConnectionFactory";
  public final static String QUEUE="javax.jms.exampleQueue";
  public final static String PARSER="com.sun.xml.parser.ValidatingParser";

  private QueueConnectionFactory qconFactory;
  private QueueConnection qcon;
  private QueueSession qsession;
  private QueueReceiver qreceiver;
  private QueueSender qsender;
  private Queue queue;
  private TextMessage msg;
  private boolean quit = false;

  /**
   * Called when a message is received from the JMS message queue. (MessageListener interface)
   */
  public void onMessage(Message message)
  {
    try {
      // obtain a DOM parser and associate the resolver and document builder
      Parser parser = new com.sun.xml.parser.Parser();

      // use custom entity resolver to locate the DTD when parsing
      ResourceEntityResolver rer = new ResourceEntityResolver();
      rer.addEntityResource("weblogic-examples-xml-jms-dtd", "workflow.dtd", getClass());
      parser.setEntityResolver(rer);

      XmlDocumentBuilder builder = new XmlDocumentBuilder();
      builder.setDisableNamespaces(true);
      builder.setParser(parser);

      // get the message and parse
      String msgText = ((TextMessage) message).getText();
      parser.parse(new InputSource(new StringReader(msgText)));
      XmlDocument doc =  (XmlDocument) builder.getDocument();
      Element root =  doc.getDocumentElement();

      if (root.getAttribute("message").equalsIgnoreCase("quit")) {
        synchronized(this) {
          quit = true;
          this.notifyAll(); // Notify main thread to quit
        }
      } else {

        System.out.println("\n\nYou have a message in you inbox!");
        System.out.println("From: "+ root.getAttribute("sender"));
        System.out.println("Message: "+ root.getAttribute("message"));
        System.out.println("Status of message: "+ root.getAttribute("status"));

        if (root.getAttribute("status").equals("pending approval")) {
          boolean approved = false;
          boolean denied = false;

          do {
            System.out.print("Approve (\"yes\" or \"no\"): ");

            BufferedReader msgStream = new BufferedReader(new InputStreamReader(System.in));
            String line=null;
            line = msgStream.readLine();
            if (line != null && line.trim().length() != 0) {
              approved = line.equalsIgnoreCase("yes");
              denied = line.equalsIgnoreCase("no");
              if (approved || denied) {
                msg.setStringProperty("messageTo", root.getAttribute("sender"));
    
                // update the original xml doc 
                root.setAttribute("status", approved ? "approved" : "approval denied");
                root.setAttribute("sender", "Admin");

                // send xml doc back to JMS queue
                StringWriter sw = new StringWriter();
                doc.write(sw);
                msg.setText(sw.toString());
                System.out.println("Message status updated. Returning message to sender.");
                qsender.send(msg);
              }
            }
          } while (!approved && !denied);
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
    } 
  }

  /**
   * Create all the necessary objects for sending and receiving
   * messages from a JMS queue.
   */
  public void init(Context ctx, String queueName)
       throws NamingException, JMSException
  {
    qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);
    qcon = qconFactory.createQueueConnection();
    qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
    try {
      queue = (Queue) ctx.lookup(queueName);
    } catch (NamingException ne) {
      queue = qsession.createQueue(queueName);
      ctx.bind(queueName, queue);
    }
    String selector = "messageTo = 'admin'";
    qreceiver = qsession.createReceiver(queue, selector);
    qreceiver.setMessageListener(this);
    qsender = qsession.createSender(queue);
    msg = qsession.createTextMessage();
    qcon.start();
  }

  /**
   * Close JMS objects.
   */
  public void close()
       throws JMSException
  {
    qreceiver.close();
    qsender.close();
    qsession.close();
    qcon.close();
  }


  /**
   * Runs this example from the command line. 
   */
  public static void main(String[] args)
       throws Exception 
  {
    if (args.length != 1) {
      System.out.println("Usage: java examples.jms.queue.QueueReceive WebLogicURL");
      return;
    }
    InitialContext ic = getInitialContext(args[0]);

    AdminClient ac  = new AdminClient();
    ac.init(ic, QUEUE);
    
    System.out.println("AdminClient ready to recieve messages.");
    // Wait until a "quit" message has been received.
    synchronized(ac) {
      while (! ac.quit) {
        try {
          ac.wait();
        } catch (InterruptedException ie) {}
      }
    }
    Thread.sleep(2000);
    ac.close();
  }

  // get an initial context to the server
  private static InitialContext getInitialContext(String url)
       throws NamingException
  {
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
    env.put(Context.PROVIDER_URL, url);
    return new InitialContext(env);
  }

}




