package org.apache.soap.server;

import java.util.*;
import javax.jms.*;
import javax.naming.*;
import java.net.*;
import java.io.*;
import javax.mail.MessagingException;
import org.apache.soap.*;
import org.apache.soap.rpc.*;
import org.apache.soap.transport.*;
import org.apache.soap.transport.jms.*;
import org.apache.soap.util.*;
import org.apache.soap.util.net.*;

/**
 * This class can be used as a bridge to relay SOAP messages received via
 * JMS to an HTTP SOAP listener. This is pretty much like the SMTP2HTTPBridge.
 * The return is either put into a JMS queue specified in the message header,
 * or can be sent to a default, when starting this services, if the
 * message header doesn't specify anything.
 *
 * @author Hari Nam Singh (hsingh@elite.com)
 */
public class JMS2HTTPBridge implements Runnable {

    private String  _requestQueue;
    private String  _defaultResponseQueue;
    private long    _pollDelayMillis;
    private URL     _routerURL;
    private boolean _shutdown;
    private String  _jndiFactory;
    private String  _jndiURL;
    private JMSUtil         _jmsHelper;


    /**
     * Creates a bridge. Call the run method to actually start polling.
     * It reads a request from one JMS queue, posts to HTTP, and puts the
     * response either in a queue specified in the JMS headers, or a
     * default queue defined by the start parameters of the bridge.
     * @param pollDelayMillis The dealy in millisenconds between polling the
     *      JMS queue.
     * @param requestQueue The JNDI name to look up the queue, where SOAP
     *      requests will be found
     * @param defaultResponseQueue The queue to which responses will be posted,
     *      if the JMS message didn't specify something else.
     * @param routerURL The url to where soap requests will be posted for handeling.
     */
    public JMS2HTTPBridge(long pollDelayMillis, String requestQueue,
                          String defaultResponseQueue, URL routerURL,
                          String jndiFactory, String jndiURL) {
        _pollDelayMillis = pollDelayMillis;
        _requestQueue    = requestQueue;
        _defaultResponseQueue = defaultResponseQueue;
        _routerURL       = routerURL;
        _jndiFactory     = jndiFactory;
        _jndiURL         = jndiURL;
    }

    /**
     * Initializes the connection to the JMS queue
     */
    /* private void initialize () throws NamingException, JMSException {
        Context ctx      = JMSUtil.lookupContext(_jndiFactory, _jndiURL);
        _queue           = JMSUtil.lookupQueue(_requestQueue, ctx);
        _queueConnection = JMSUtil.lookupQueueConnection(ctx);
        QueueSession session = _queueConnection.createQueueSession(false,
                                                     Session.AUTO_ACKNOWLEDGE);
        _queueReceiver   = session.createReceiver(_queue);
        _queueConnection.start();
    }*/


    /**
     * Runs, until shutdown is called, and keeps polling messages.
     */
    public void run() {
        _shutdown = false;

        try {
            _jmsHelper = new JMSUtil(_jndiFactory, _jndiURL, _requestQueue);
                          // might move this in constructor, to allow restarts
                          // of the polling, without going through the whole thing
                          // again. Though, restart is not supported for now.
        } catch(Exception ex) {
            System.err.println("Couldn't initialize JMS connection");
            ex.printStackTrace();
            System.exit(1);
        }

        System.out.println("Bridge is up and running");
        while (!_shutdown) {
            try {
                TextMessage message = (TextMessage) _jmsHelper.getQueueReceiver().receive(_pollDelayMillis);
                // don't use blocking reads, so that the system can be shut down!

                if (message != null) {
                    System.out.println("got a message");

                    // extract information from JMS message
                    HashMap headers = new HashMap();
                    Enumeration enum = message.getPropertyNames();
                    while (enum.hasMoreElements()) {
                        String key = (String) enum.nextElement(),
                               value = message.getStringProperty(key);
                        if ((key != null) && (value != null)) {
                            headers.put(key, value);
                        }
                    }
                    System.out.println("--------------Request JMS body" + message.getText());
                    String payLoad       = message.getText();
                    String actionUri     = message.getStringProperty(Constants.HEADER_SOAP_ACTION);
                    String responseQueue = message.getStringProperty(JMSConstants.JMS_RETURN_QUEUE);
                    if (responseQueue == null) {
                        // default to standard response queue
                        System.out.println("using default response Queue " + _defaultResponseQueue);
                        responseQueue = _defaultResponseQueue;
                    }

                    // forward processing to http post
                    Hashtable postHeaders = new Hashtable();
                    if (actionUri != null) {
                        postHeaders.put(Constants.HEADER_SOAP_ACTION, actionUri);
                    }
                    TransportMessage response;
                    SOAPContext ctx;
                    try {
                        TransportMessage tmsg = new TransportMessage(payLoad
                                                                    , new SOAPContext()
                                                                    , postHeaders);
                        tmsg.save();
                        response = HTTPUtils.post(_routerURL, tmsg, 30000, null, 0);
                        ctx = response.getSOAPContext();
                        payLoad = IOUtils.getStringFromReader(response.getEnvelopeReader());
                    } catch(SOAPException ex) {
                        ex.printStackTrace();
                    } catch(IOException ex) {
                        ex.printStackTrace();
                    } catch(MessagingException ex) {
                        ex.printStackTrace();
                    }

                    System.out.println(payLoad);

                    // building JMS response
                    JMSUtil responseHelper = _jmsHelper.createJMSUtil(responseQueue);
                    TextMessage message2 = responseHelper.getQueueSession().createTextMessage();
                    message2.setText(payLoad);
                    if (actionUri != null) {
                        message2.setStringProperty(Constants.HEADER_SOAP_ACTION, actionUri);
                    }
                    message2.setJMSCorrelationID(message.getJMSMessageID());
                    responseHelper.getQueueSender().send(message2);
                    //_jmsHelper.getQueueSession().commit();
                    responseHelper.getQueueConnection().close();
                }
            } catch(JMSException ex) {
                ex.printStackTrace();
            } catch(NamingException ex) {
                ex.printStackTrace();
            }
        }
        try {
            _jmsHelper.getQueueSession().close();
        } catch(JMSException ex) {
            ex.printStackTrace();
        } catch(NamingException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Stops the polling. Call run() again to continue.
     */
    public void shutdown() {
        _shutdown = true;
    }

    /**
     * utility method that does a jndi lookup.
     */


    /**
     * Call this to start the bridge. The usuage is described,
     * when no parameters are supplied.
     */
    public static void main(String args[]) {
        if (args.length != 6) {
            // missing arguments, show proper usage
            System.err.println("Usage: java " + JMS2HTTPBridge.class.getName() + "\\");
            System.err.println("pollDelay requestQueue defaultResponseQueue routerURL \\");
            System.err.println("jndiFactory jndiUrl");
            System.exit(1);
        }

        try {
            JMS2HTTPBridge jb = new JMS2HTTPBridge(Long.parseLong(args[0]), args[1]
                                     , args[2], new URL(args[3]), args[4]
                                     , args[5]);
            new Thread(jb).start();
        } catch(MalformedURLException ex) {
            ex.printStackTrace();
        }
    }
}