All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nablarch.fw.messaging.realtime.http.client.HttpProtocolBasicClient Maven / Gradle / Ivy

The newest version!
package nablarch.fw.messaging.realtime.http.client;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;

import nablarch.core.util.FileUtil;
import nablarch.core.util.annotation.Published;
import nablarch.fw.messaging.MessagingException;
import nablarch.fw.messaging.realtime.http.dto.HttpResult;
import nablarch.fw.messaging.realtime.http.exception.HttpMessagingException;
import nablarch.fw.messaging.realtime.http.exception.HttpMessagingTimeoutException;
import nablarch.fw.messaging.realtime.http.streamio.CharHttpStreamReader;
import nablarch.fw.messaging.realtime.http.streamio.HttpInputStreamReader;
import nablarch.fw.messaging.realtime.http.streamio.HttpOutputStreamWriter;

/**
 * Http接続用クライアント。
 * 
 * @author TIS
 */
@Published(tag = "architect")
public class HttpProtocolBasicClient implements HttpProtocolClient {
    /** HTTPSで通信する際に使用する情報 */
    private SSLContext sslContext;
    /** 接続タイムアウト */
    private int connectTimeout;
    /** 読みとりタイムアウト */
    private int readTimeout;
    /** プロキシURL */
    private String proxyUrl;
    /** プロキシポート */
    private int proxyPort;
    /** コンテンツタイプ */
    private String contentType;
    /** 受け入れるデータ種別 */
    private String accept;
    /** クエリストリングをエンコードする際に使用するエンコーディング*/
    private String queryStringEncoding = "UTF-8";

    /**
     * コンストラクタ
     */
    public HttpProtocolBasicClient() {
        super();
    }

    /**
     * プロキシ情報を設定する。
     * @param url プロキシURL
     * @param port ポート番号
     */
    public void setProxyInfo(String url, int port) {
        this.proxyUrl = url;
        this.proxyPort = port;
    }

    /**
     * 接続タイムアウトを設定する。
     * @param connectTimeout 接続タイムアウト
     */
    public void setConnectTimeout(int connectTimeout) {
        this.connectTimeout = connectTimeout;
    }

    /**
     * 読み取りタイムアウトを設定する。
     * @param readTimeout 読み取りタイムアウト
     */
    public void setReadTimeout(int readTimeout) {
        this.readTimeout = readTimeout;
    }

    /**
     * コンテンツタイプを設定する。
     * @param contentType コンテンツタイプ
     */
    public void setContentType(String contentType) {
        this.contentType = contentType;
    }

    /**
     * 受け入れるデータ種別を設定する。
     * @param accept 受け入れるデータ種別
     */
    public void setAccept(String accept) {
        this.accept = accept;
    }

    /**
     * SSLContextを設定する。
     * @param sslContext SSLContext
     */
    public void setSslContext(SSLContext sslContext) {
        this.sslContext = sslContext;
    }

    /**
     * パラメータをエンコードする際に使用する文字コードを設定する。
     * @param queryStringEncoding 文字コード
     */
    public void setQueryStringEncoding(String queryStringEncoding) {
        this.queryStringEncoding = queryStringEncoding;
    }

    /**
     * HTTP通信を行う。
     * @param httpMethod HTTPメソッド
     * @param url 接続先
     * @param headerInfo HttpHeadderに渡す情報
     * @param urlParams URLパラメータ。送信するパラメータがない場合は、null可。
     * @param writer StreamWritter。送信するBody部が存在しない場合は、null可。
     * @param reader 応答の読み込みに使用するreader
     * @return レスポンスコード
     * @throws HttpMessagingException 何らかの理由(接続タイムアウト、ソケットの予期せぬclose等)で通信が失敗した場合に送出される。
     */
    public HttpResult execute(HttpRequestMethodEnum httpMethod, String url, Map> headerInfo,
            Map urlParams, HttpOutputStreamWriter writer, HttpInputStreamReader reader)
                    throws HttpMessagingException {

        //通信結果
        HttpResult result = new HttpResult();
        // 接続先URL
        String targetUrl = url;
        //ヘッダ情報
        Map> headeInfo = null;
        //ステータスコード
        Integer responseCode = null;
        //レスポンス本体
        Object responseObject = null;
        // パラメータが設定されていたら、URLにパラメータを追加
        if (urlParams != null && !urlParams.isEmpty()) {
            targetUrl = targetUrl + "?" + paramStringBuilder(urlParams);
        }
        
        if (reader == null) {
            //リーダーが指定されていない場合は、新たにリーダーを生成する。
            reader = new CharHttpStreamReader();
        }
        
        HttpURLConnection con = null;
        OutputStream outputStream = null;
        InputStream inputStream = null;
        try {
            //書き込みHTTPステータスコードとヘッダ情報の読み取り
            con = createHttpConnection(targetUrl, httpMethod, headerInfo);
            if (writer != null) {
                outputStream = con.getOutputStream();
                writer.writeStream(outputStream);
            }
            //以降、Streamへの書き込みはないのでcloseする。
            FileUtil.closeQuietly(outputStream);
            outputStream = null;

            //HTTPステータスコードとヘッダ情報の読み取り
            responseCode = con.getResponseCode();
            headeInfo = con.getHeaderFields();
            reader.setHeaderInfo(headeInfo);

            //body部の読み取り
            inputStream = con.getInputStream();
            responseObject = reader.readInputStream(inputStream);
        } catch (SocketTimeoutException e) {
            throw new HttpMessagingTimeoutException("Time-out occurs.", targetUrl, responseCode, e);
        } catch (IOException ie) {
            InputStream es = null;
            try {
                //エラー用ストリームからの読み取りを試す。
                //(何種類かのHTTPステータスコードについては、Body部の読み取り時にこのロジックに到達する)
                if (con != null) {
                    es = con.getErrorStream();
                }
                if (es != null) {
                    //エラー用ストリームから読み取れた場合は、処理を続行する。
                    responseObject = reader.readInputStream(es);
                } else {
                    //getErrorStream()からも読み取れない場合は、例外を送出する。
                    throw new HttpMessagingException(targetUrl, responseCode, ie);
                }
            } catch (SocketTimeoutException e) {
                throw new HttpMessagingTimeoutException("Time-out occurs.", targetUrl, responseCode, e);
            } catch (IOException e) {
                //getErrorStream()からも読み取れない場合は、例外を送出する。
                throw new HttpMessagingException(targetUrl, responseCode, e);
            } finally {
                FileUtil.closeQuietly(es);
            }
        } finally {
          //正常ケースでoutputStreamを閉じた場合、この行に到達した時点でnullが代入されているため、「2回stream閉じようとして例外が発生」ということはない
            FileUtil.closeQuietly(outputStream); 
            
            FileUtil.closeQuietly(inputStream);
            if (con != null) {
                con.disconnect();
            }
        }

        //通信結果設定
        result.setResponseCode(responseCode);
        result.setHeaderInfo(headeInfo);
        result.setReadObject(responseObject);
        return result;
    }

    /**
     * HttpURLConnectionを作成する。
     * 
     * @param targetUrl 接続先
     * @param method 接続メソッド
     * @param headerInfo HttpHeadderに渡す情報
     * @return HttpURLConnection
     * @throws IOException 接続例外
     */
    protected HttpURLConnection createHttpConnection(String targetUrl,
            HttpRequestMethodEnum method, Map> headerInfo) throws IOException {

        URL url = new URL(targetUrl);

        HttpURLConnection con;
        if (proxyUrl != null) {
            Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyUrl, proxyPort));
            con = (HttpURLConnection) url.openConnection(proxy);
        } else {
            con = (HttpURLConnection) url.openConnection();
        }

        if (con instanceof HttpsURLConnection) {
            if (sslContext != null) {
                ((HttpsURLConnection) con).setSSLSocketFactory(sslContext.getSocketFactory());
            }
        }
        con.setConnectTimeout(connectTimeout);
        con.setReadTimeout(readTimeout);

        // Header情報を設定
        con.setRequestProperty("Content-type", contentType);
        con.setRequestProperty("Accept", accept);
        // 追加のHeader情報を設定
        for (Entry> headerInfoEntrySet : headerInfo.entrySet()) {
            for (String value : headerInfoEntrySet.getValue()) {
                con.addRequestProperty(headerInfoEntrySet.getKey(), value);
            }
        }

        // GET以外はOutputする
        if (!method.equals(HttpRequestMethodEnum.GET)) {
            con.setDoOutput(true);
        }
        con.setRequestMethod(method.toString());

        return con;
    }

    /**
     * URLにパラメータを文字列として埋め込む場合の文字列を作成して返却する。
     * 
     * @param paramData 作成元パラメータ
     * @return 作成結果
     */
    protected String paramStringBuilder(Map paramData) {
        StringBuilder sbParam = new StringBuilder();

        for (Entry entry : paramData.entrySet()) {
            if (sbParam.length() != 0) {
                sbParam.append("&");
            }
            String value = null;
            try {
                value = URLEncoder.encode(entry.getValue(), queryStringEncoding);
            } catch (UnsupportedEncodingException e) {
                throw new MessagingException(e);
            }
            sbParam.append(String.format("%s=%s", entry.getKey(), value));
        }

        return sbParam.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy