/*
 * Copyright (c) 2007, 2009, Oracle and its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

/*
 * $Id: HttpClient.java 62602 2011-04-21 14:51:41Z kgrucci $
 */

/* Copyright (c) 2003 Oracle Corporation.  All rights reserved.  */
package com.sun.ts.tests.jaxws.sharedclients;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.nio.charset.Charset;

import com.sun.ts.lib.harness.EETest;
import com.sun.ts.lib.util.TestUtil;

import java.io.Serializable;

public class HttpClient implements Serializable {

    private final static String DEFAULT_CHARSET = "UTF-8";

    /**
     * HTTP GET method.
     */
    public static final String HTTP_METHOD_GET = "GET";

    /**
     * HTTP POST method.
     */
    public static final String HTTP_METHOD_POST = "POST";

    /**
     * The HTTP method.
     */
    private String method;

    /**
     * The HTTP headers.
     */
    private HashMap headers;

    /**
     * The URL.
     */
    private String url;

    /**
     * The Charset.
     */
    private Charset cs;

    private HttpURLConnection conn;

    /**
     * Constructs a new HttpRequest instance with the specified URL.
     *
     * @param url the URL.
     */
    public HttpClient() throws EETest.Fault {
        super();
        this.method = HTTP_METHOD_POST;
        headers = new HashMap();
        headers.put("SOAPAction","\"\"");
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public Charset getCharset() {
        return cs;
    }

    public void setCharset(Charset cs)
    {
	this.cs = cs;
    }

    private String getCharsetAsName() {
	if (cs == null)
	    return DEFAULT_CHARSET;
	else
	    return cs.name().toUpperCase();
    }

    /**
     * Sets the HTTP request method.
     *
     * @param method the HTTP request method.
     */
    public void setMethod(String method) {
        if (method != null) {
            this.method = method;
        } else {
            this.method = HTTP_METHOD_POST;
        }
    }

    /**
     * Returns the HTTP request method.
     *
     * @return the HTTP request method.
     */
    public String getMethod() {
        return method;
    }

    /**
     * Adds the specified HTTP header.
     *
     * @param name the header name.
     * @param value the header value.
     */
    public void addHeader(String name, String value) {
        name = properCase(name);
        String current = (String)headers.get(name);
        if (current != null) {
            value = current + ", " + value;
        }
        headers.put(name, value);
    }

    /**
     * Sets the specified HTTP header.
     *
     * @param name the header name.
     * @param value the header value.
     */
    public void setHeader(String name, String value) {
        headers.put(properCase(name), value);
    }

    /**
     * Sets the specified HTTP header.
     *
     * @param name the header name.
     * @param value the header value.
     */
    public void setHeaderCaseAsIs(String name, String value) {
        headers.put(name, value);
    }

    /**
     * Returns the HTTP status code.  Until the request has completed, this
     * value is 200.
     *
     * @return the HTTP status code.
     */
    public int getStatusCode() throws IOException{
        return conn.getResponseCode();
    }

    /**
     * Returns the HTTP status message.  Until the request has completed, this
     * value is OK.
     *
     * @return the HTTP status message.
     */
    public String getStatusMessage() throws IOException{
        return conn.getResponseMessage();
    }

    /**
     * Interacts with the server by sending the request and receiving the
     * response.
     *
     * @param is the request message input stream.
     *
     * @throws java.io.IOException
     */
    public InputStream makeRequest(InputStream messageContent) throws IOException {
	String name = getCharsetAsName();
	TestUtil.logMsg("Charset name=" + name);
        addHeader("Content-Type","text/xml; charset="+name);
        conn = (HttpURLConnection)new URL(url).openConnection();
        sendRequest(messageContent);
        return receiveResponse();
    }

    /**
     * Sends the request to the server.
     *
     * @param conn the HTTP URL connection.
     * @param is the request message input stream.
     *
     * @throws java.io.IOException
     */
    protected void sendRequest(InputStream is) throws IOException {
        conn.setRequestMethod(method);
        Iterator iterator = headers.keySet().iterator();
        while (iterator.hasNext()) {
            String name = (String)iterator.next();
            String value = (String)headers.get(name);
	    TestUtil.logMsg("Setting HTTP_HEADER: "+name+"="+value);
            conn.setRequestProperty(name, value);
        }
        if (is != null) {
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            transfer(is, os);
        }
    }

    /**
     * Receives the response from the server.  If no content is returned, this
     * method returns null.
     *
     * @param conn the HTTP URL connection.
     *
     * @return the response message input stream.
     *
     * @throws java.io.IOException
     */
    protected InputStream receiveResponse() throws IOException {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        byte[] response;
        InputStream is;
        try {
            try {
                is = conn.getInputStream();
            } catch (IOException e) {
                is = conn.getErrorStream();
            }
	    if (is == null) return null;
            transfer(is, os);
            response = os.toByteArray();
        } catch (IOException e) {
              TestUtil.printStackTrace(e);
            response = null;
        }
        return (response != null ? new ByteArrayInputStream(response) : null);
    }

    /**
     * Transfers all data from the specified input stream to the specified
     * output stream.
     *
     * @param is the input stream.
     * @param os the output stream.
     *
     * @throws java.io.IOException
     */
    protected void transfer(InputStream is, OutputStream os) throws IOException {
        byte[] buffer = new byte[1024];
        int length;
        do {
	    try {
              length = is.read(buffer);
              if (length > 0) {
                os.write(buffer, 0, length);
              }
	    } catch (IOException e) {
		return;
	    }
        } while (length > 0);
        os.flush();
    }

    /**
     * Proper cases an HTTP header name (e.g. Accept-Language).
     *
     * @param name the name.
     * @return the proper cased name.
     */
    protected String properCase(String name) {
        StringBuffer buffer = new StringBuffer(name.length());
        char previous = '-';
        for (int i = 0; i < name.length(); i++) {
            char c = name.charAt(i);
            if (previous == '-') {
                buffer.append(Character.toUpperCase(c));
            } else {
                buffer.append(Character.toLowerCase(c));
            }
            previous = c;
        }
        return buffer.toString();
    }

    public void logMessageInHarness(InputStream message) {
	//This method is deprecated. Logging is done in SOAPClient. Set message=null.
    }

    public String getResponseHeader(String name){
        return conn.getHeaderField(name);
    }
}
