package org.apache.soap.transport.jms;

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

/**
 * SOAPJMSConnection is an implementation of the SOAPTransport interface for JMS.
 * Similar to the SOAPSMTPConnection.
 */
public class SOAPJMSConnection implements SOAPTransport {
    private BufferedReader _responseReader;
    private Hashtable      _responseHeaders;
    private SOAPContext    _responseContext;

    private String _requestQueue,
                   _responseQueue,
                   _jndiFactory;
    private String  _jndiURL;
    private JMSUtil _jmsRequestHelper,
                   _jmsResponseHelper;
    private static int _counter = 0; // debug only



    /**
     * Constructor sets up this JMS connection for sending and receiving.
     * I guess, the same connection could be reused, once created for
     * multiple SOAP requests. I'm not sure, if this will change in the future.
     * This SOAP implementation does a blocking call to wait for a message in
     * return. If no messages is returned, it will wait for ever.
     *
     * @param requestQueue JNDI name for the request queue - Queue to which
     *      SOAP requests are posted.
     * @param responseQueue JNDI name for the queue, where responses are fetched.
     * @param jndiFactory JNDI INITIAL_CONTEXT_FACTORY
     * @param jndiURL The JDNI PROVIDER_URL.
     */
    public SOAPJMSConnection(String requestQueue,
                             String responseQueue,
                             String jndiFactory,
                             String jndiURL) {
        _requestQueue  = requestQueue;
        _responseQueue = responseQueue;
        _jndiFactory   = jndiFactory;
        _jndiURL       = jndiURL;
        _jmsRequestHelper = new JMSUtil(jndiFactory, jndiURL, requestQueue);
        _jmsResponseHelper = _jmsRequestHelper.createJMSUtil(responseQueue);
    }


    /**
     * This method is used to request that an envelope be sent.
     * Note: Sending SOAPContext is not implemented yet.
     */
    public void send(URL toAddr, String actionURI, Hashtable headers,
                     Envelope env, SOAPMappingRegistry smr, SOAPContext ctx) {
        System.out.println("send called " + (_counter++));
        try {
            // send JMS SOAP message
            TextMessage message = _jmsRequestHelper.getQueueSession().createTextMessage();
            StringWriter writer = new StringWriter();
            try {
                env.marshall(writer, smr);
            } catch(IOException ex) {
                ex.printStackTrace();
            }
            message.setText(writer.toString());
            System.out.println("response Queue is " + _responseQueue);
            message.setStringProperty(JMSConstants.JMS_RETURN_QUEUE, _responseQueue);
            message.setStringProperty(Constants.HEADER_SOAP_ACTION, actionURI);
            _jmsRequestHelper.getQueueSender().send(message);

            // wait for JMS SOAP response and set the instance variables with
            // the values.
            // this is currently pretty bad, as it is not multi-threadable to
            // check that it got the right message, and use transaction to keep
            // wrong messages inside the queue, without the potential of loosing
            // them in a system crash.
            message = (TextMessage) _jmsResponseHelper.getQueueReceiver().receive();
            System.out.println("JMS body is " + message.getText());
            _responseHeaders = new Hashtable();
            actionURI = message.getStringProperty(Constants.HEADER_SOAP_ACTION);
            if (actionURI != null) {
                _responseHeaders.put(Constants.HEADER_SOAP_ACTION, actionURI);
            }
            try {
                _responseContext = new SOAPContext();
                _responseContext.setRootPart(message.getText(), "text/xml");
            } catch(IOException ex) {
                ex.printStackTrace();
            }
            _responseReader = new BufferedReader(new StringReader(message.getText()));
        } catch(JMSException ex) {
            ex.printStackTrace();
        } catch(NamingException ex) {
            ex.printStackTrace();
        } catch(MessagingException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Get the headers after calling receive.
     */
    public Hashtable getHeaders() {
        return _responseHeaders;
    }

    /**
     * Gets the SOAPContext after calling receive().
     */
    public SOAPContext getResponseSOAPContext() {
        return _responseContext;
    }

    /**
     * Gets a reader to the response
     */
    public BufferedReader receive() {
        return _responseReader;
    }
}