/*
 */
/*
 * This is a simple graphical Java program that allows you to send
 * custom SOAP requests to a server and view the responses. You can
 * either type the request in by hand or read one in from a file.
 * For convenience, you also have the ability to send the request
 * through a proxy server and set the socket timeout.
 *
 * While this program was written with SOAP requests in mind, it
 * could be easily modified to handle other similar types of requests.
 * Play around with it a little. Have some fun.
 *
 * Version History:
 * version 1.0 -- initial release
 * version 1.1 -- changed HTTP header so it uses \r\n for line separators
 *                instead of just \n (per the HTTP specification)
 *             -- added the repaintNow method to refresh the text in the
 *                JTextArea before the events finish firing
 *             -- added a global variable to remember the last directory
 *                we used in a given session
 *
 * Julian Robichaux -- http://www.nsftools.com
 * version 1.1, February 1, 2003
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.*;
import java.io.*;

public class SoapTester extends JFrame {
	private JTextField soapUrlField;
	private JTextField soapActionField;
	private JTextField proxyServerField;
	private JTextField proxyPortField;
	private JTextField socketTimeoutField;
	private JScrollPane sendScroll;
	private JTextArea soapSentArea;
	private JScrollPane receiveScroll;
	private JTextArea soapReceivedArea;
	
	private String lastDir = null;
	public static final int DEFAULT_TIMEOUT = 20;
	

	public static void main (String[] args) {
		// when we're starting up, just create a new instance of
		// SoapTester and sit back and wait
		SoapTester st = new SoapTester();
	}
	
	public SoapTester() {
		setTitle("SOAP Tester Client");
		
		JPanel north = new JPanel();
		JPanel center = new JPanel();
		JPanel south = new JPanel();
		
		// this will be all the stuff at the top of the window
		JPanel northTop = new JPanel(new FlowLayout(FlowLayout.LEFT));
		JPanel northCenter = new JPanel(new FlowLayout(FlowLayout.LEFT));
		JPanel northBottom = new JPanel(new FlowLayout(FlowLayout.LEFT));
		
		northTop.add(new JLabel("SOAP URL:"));
		soapUrlField = new JTextField("http://", 50);
		northTop.add(soapUrlField);
		
		northCenter.add(new JLabel("SOAPAction Header:"));
		soapActionField = new JTextField("", 45);
		northCenter.add(soapActionField);
		
		northBottom.add(new JLabel("Proxy Server (optional):"));
		proxyServerField = new JTextField("", 15);
		northBottom.add(proxyServerField);
		northBottom.add(new JLabel("Proxy Port:"));
		proxyPortField = new JTextField("", 5);
		northBottom.add(proxyPortField);
		northBottom.add(new JLabel("Socket Timeout (seconds):"));
		socketTimeoutField = new JTextField(String.valueOf(DEFAULT_TIMEOUT), 3);
		northBottom.add(socketTimeoutField);
		
		north.setLayout(new BorderLayout());
		north.setBorder(BorderFactory.createEtchedBorder());
		north.add(northTop, BorderLayout.NORTH);
		north.add(northCenter, BorderLayout.CENTER);
		north.add(northBottom, BorderLayout.SOUTH);
		
		
		// this is all the stuff in the middle (we'll be nice and
		// give the user a sample SOAP request to start off with)
		StringBuffer soapExample = new StringBuffer("");
		soapExample.append("\n");
		soapExample.append("\n");
		soapExample.append("  \n");
		soapExample.append("    <...YOUR SOAP HERE...>\n");
		soapExample.append("  \n");
		soapExample.append("\n");
		
		JPanel centerTop = new JPanel(new BorderLayout());
		JPanel centerBottom = new JPanel(new BorderLayout());
		
		soapSentArea = new JTextArea(soapExample.toString(), 10, 30);
		soapSentArea.setFont( new Font("MonoSpaced", Font.PLAIN, 12));
		sendScroll = new JScrollPane(soapSentArea);
		centerTop.add(new JLabel("SOAP To Send", JLabel.LEFT), BorderLayout.NORTH);
		centerTop.add(sendScroll, BorderLayout.SOUTH);
		
		soapReceivedArea = new JTextArea("", 10, 30);
		soapReceivedArea.setFont( new Font("MonoSpaced", Font.PLAIN, 12));
		receiveScroll = new JScrollPane(soapReceivedArea);
		centerBottom.add(new JLabel("SOAP Response", JLabel.LEFT), BorderLayout.NORTH);
		centerBottom.add(receiveScroll, BorderLayout.SOUTH);
		
		center.setLayout(new GridLayout(2, 1, 10, 10));
		center.add(centerTop);
		center.add(centerBottom);
		
		// and this is all the stuff at the bottom
		JButton getFile = new JButton("Read SOAP Request From File");
		getFile.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				getSoapFile();
			}
		});
		south.add(getFile);
		JButton send = new JButton("Send SOAP Data");
		send.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				sendData();
			}
		});
		south.add(send);
		JButton bye = new JButton("Exit");
		bye.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		});
		south.add(bye);
		
		
		// add all the components to the container that we'll display
		Container content = getContentPane();
		content.setLayout(new BorderLayout(10, 10));
		content.add(north, BorderLayout.NORTH);
		content.add(center, BorderLayout.CENTER);
		content.add(south, BorderLayout.SOUTH);
		
		// make sure we exit properly when the window is closed
		addWindowListener( new WindowAdapter() {
			public void windowClosed(WindowEvent e) {
				System.exit(0);
			}
		});
		setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		
		// and let's see what we've got
		pack();
		show();
		
	}
	
	
	void getSoapFile () {
		// use the java.awt FileDialog class to get a file name from the user
		FileDialog fd = new FileDialog(this, "Open File", FileDialog.LOAD);
		if (lastDir != null)
			fd.setDirectory(lastDir);
		fd.show();
		
		String dir = fd.getDirectory();
		String fileName = fd.getFile();
		fd.dispose();
		
		// if the user didn't select anything, just exit
		//soapSentArea.setText("Directory: " + dir + "\n");
		//soapSentArea.append("File: " + fileName + "\n");
		if ((fileName == null) || (fileName.length() == 0))
			return;
		
		// try to open the file and read everything from it (we're
		// assuming this is a text file, because a SOAP request is
		// text...)
		lastDir = dir;
		soapSentArea.setText("");
		File f = null;
		BufferedReader in = null;
		try {
			f = new File(dir, fileName);
			in = new BufferedReader( new InputStreamReader(new FileInputStream(f)) );
			
			String line = "";
			while ((line = in.readLine()) != null)
				soapSentArea.append(line + "\n");
			
			in.close();
		} catch (Exception e) {
			soapSentArea.append("\n" + e.getClass().getName() + 
									" Error: " + e.getMessage() + "\n");
		} finally {
			try { in.close(); } catch (Exception e) {}
		}
		
		// make sure we're at the top of the text area when we return
		soapSentArea.setCaretPosition(0);
	}
	
	
	void sendData() {
		// send the SOAP data to the specified host.
		
		// define the reader and the writer up here, so we can access
		// them in the finally section of the try block (we're using
		// a BufferedReader to grab the response from the remote server
		// because we're assuming that the SOAP response is text; you
		// should change it to a BufferedInputStream if you're expecting
		// non-text data as a response for some reason)
		BufferedReader in = null;
		PrintWriter out = null;
		soapReceivedArea.setText("waiting for response...\n");
		soapReceivedArea.setCaretPosition(0);
		repaintNow(soapReceivedArea);
		repaintNow(receiveScroll);
		
		try {
			// get the parts of the URL (we'll need them when we write the header)
			URL url = new URL(soapUrlField.getText());
			String urlString = url.toString();
			String hostName = url.getHost();
			int hostPort = (url.getPort() > 0) ? url.getPort() : 80;
			String urlPath = url.getPath();
			if (!urlPath.startsWith("/"))
				urlPath = "/" + urlPath;
			
			// get the proxy server information, if any
			String proxyServer = proxyServerField.getText();
			int proxyPort = 0;
			if (proxyServerField.getText().length() > 0)  {
				try { proxyPort = Integer.parseInt(proxyPortField.getText()); }
				catch (Exception e) {}
			}
			
			// create all the header information we'll need
			String body = soapSentArea.getText();
			StringBuffer header = new StringBuffer("");
			header.append("POST " + urlPath + " HTTP/1.0\r\n");
			header.append("Host: " + hostName + ":" + hostPort + "\r\n");
			header.append("User-Agent: JavaSoapTester1_0\r\n");
			header.append("Content-Type: text/xml; charset=utf-8\r\n");
			header.append("Content-Length: " + body.length() + "\r\n");
			header.append("SOAPAction: \"" + soapActionField.getText() + "\"\r\n");
			header.append("\r\n");
			
			// open a socket and get the input and output streams (we're using
			// a raw Socket instead of an HttpUrlConnection so we can set a
			// timeout -- which is why we had to create all the header information
			// manually)
			Socket s = null;
			if ((proxyServer.length() > 0) && (proxyPort > 0))
				s = new Socket(proxyServer, proxyPort);
			else
				s = new Socket(hostName, hostPort);
			
			// set the timeout
			int socketTimeout;
			try {
				socketTimeout = Integer.parseInt(socketTimeoutField.getText(), 10) * 1000;
			} catch (Exception e) {
				socketTimeout = DEFAULT_TIMEOUT * 1000;
			}
			s.setSoTimeout(socketTimeout);
			
			// get the streams
			in = new BufferedReader( new InputStreamReader(s.getInputStream()) );
			out = new PrintWriter( s.getOutputStream(), true );
			
			// send the request to the output stream
			out.print(header.toString() + body);
			out.flush();
			
			// and get the response from the input stream
			String line = "";
			soapReceivedArea.setText(line);
			while ((line = in.readLine()) != null)  {
				soapReceivedArea.append(line + "\n");
				if (socketTimeout == 0)
					repaintNow(soapReceivedArea);
			}
			
			out.close();
			in.close();
			
		} catch (Exception e) {
			soapReceivedArea.append("\n" + e.getClass().getName() + 
									" Error: " + e.getMessage() + "\n");
		} finally {
			try { out.close(); } catch (Exception e) {}
			try { in.close(); } catch (Exception e) {}
		}
		
		// make sure we're at the top of the text area when we return
		soapReceivedArea.setCaretPosition(0);
	}
	
	
	private void repaintNow (JComponent jc) {
		// immediately sets the text of a JComponent while an event is
		// still firing (otherwise, you have to wait for the event to
		// finish before the component is actually repainted)
		jc.paintImmediately(jc.getLocation().x, 
							jc.getLocation().y, 
							jc.getSize().width, 
							jc.getSize().height);
	}
	
	
}