Package org.restlet.ext.net.internal

Source Code of org.restlet.ext.net.internal.HttpUrlConnectionCall

/**
* Copyright 2005-2011 Noelios Technologies.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL 1.0 (the
* "Licenses"). You can select the license that you prefer but you may not use
* this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0.html
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1.php
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1.php
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.noelios.com/products/restlet-engine
*
* Restlet is a registered trademark of Noelios Technologies.
*/

package org.restlet.ext.net.internal;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.logging.Level;

import org.restlet.Request;
import org.restlet.Response;
import org.restlet.Uniform;
import org.restlet.data.Parameter;
import org.restlet.data.Protocol;
import org.restlet.data.Status;
import org.restlet.engine.Edition;
import org.restlet.engine.adapter.ClientCall;
import org.restlet.engine.header.HeaderConstants;
import org.restlet.engine.util.SystemUtils;
import org.restlet.ext.net.HttpClientHelper;
import org.restlet.representation.Representation;
import org.restlet.util.Series;

/**
* HTTP client connector call based on JDK's java.net.HttpURLConnection class.
* On the GAE edition, it also supports the SDC protocol by setting
* automatically the special "use_intranet" header.
*
* @author Jerome Louvel
*/
public class HttpUrlConnectionCall extends ClientCall {

    /** The wrapped HTTP URL connection. */
    private final HttpURLConnection connection;

    /** Indicates if the response headers were added. */
    private volatile boolean responseHeadersAdded;

    /**
     * Constructor.
     *
     * @param helper
     *            The parent HTTP client helper.
     * @param method
     *            The method name.
     * @param requestUri
     *            The request URI.
     * @param hasEntity
     *            Indicates if the call will have an entity to send to the
     *            server.
     * @throws IOException
     */
    public HttpUrlConnectionCall(HttpClientHelper helper, String method,
            String requestUri, boolean hasEntity) throws IOException {
        super(helper, method, requestUri);

        if (requestUri.startsWith("http")) {
            URL url = new URL(requestUri);
            this.connection = (HttpURLConnection) url.openConnection();

            // These properties can only be used with Java 1.5 and upper
            // releases
            int majorVersionNumber = SystemUtils.getJavaMajorVersion();
            int minorVersionNumber = SystemUtils.getJavaMinorVersion();
            if ((majorVersionNumber > 1)
                    || ((majorVersionNumber == 1) && (minorVersionNumber >= 5))) {
                this.connection.setConnectTimeout(getHelper()
                        .getSocketConnectTimeoutMs());
                this.connection.setReadTimeout(getHelper().getReadTimeout());
            }

            this.connection.setAllowUserInteraction(getHelper()
                    .isAllowUserInteraction());
            this.connection.setDoOutput(hasEntity);
            this.connection.setInstanceFollowRedirects(getHelper()
                    .isFollowRedirects());
            this.connection.setUseCaches(getHelper().isUseCaches());
            this.responseHeadersAdded = false;

            if (this.connection instanceof javax.net.ssl.HttpsURLConnection) {
                setConfidential(true);
                javax.net.ssl.HttpsURLConnection https = (javax.net.ssl.HttpsURLConnection) this.connection;
                org.restlet.ext.ssl.SslContextFactory sslContextFactory = org.restlet.ext.ssl.internal.SslUtils
                        .getSslContextFactory(getHelper());

                if (sslContextFactory != null) {
                    try {
                        javax.net.ssl.SSLContext sslContext = sslContextFactory
                                .createSslContext();
                        https.setSSLSocketFactory(sslContext.getSocketFactory());
                    } catch (Exception e) {
                        throw new RuntimeException(
                                "Unable to create SSLContext.", e);
                    }
                }

                javax.net.ssl.HostnameVerifier verifier = helper
                        .getHostnameVerifier();

                if (verifier != null) {
                    https.setHostnameVerifier(verifier);
                }
            }
        } else {
            throw new IllegalArgumentException(
                    "Only HTTP or HTTPS resource URIs are allowed here");
        }
    }

    /**
     * Returns the connection.
     *
     * @return The connection.
     */
    public HttpURLConnection getConnection() {
        return this.connection;
    }

    /**
     * Returns the HTTP client helper.
     *
     * @return The HTTP client helper.
     */
    @Override
    public HttpClientHelper getHelper() {
        return (HttpClientHelper) super.getHelper();
    }

    /**
     * Returns the response reason phrase.
     *
     * @return The response reason phrase.
     */
    @Override
    public String getReasonPhrase() {
        try {
            return getConnection().getResponseMessage();
        } catch (IOException e) {
            return null;
        }
    }

    @Override
    protected Representation getRepresentation(InputStream stream) {
        Representation r = super.getRepresentation(stream);
        return new ConnectionClosingRepresentation(r, getConnection());
    }

    @Override
    public WritableByteChannel getRequestEntityChannel() {
        return null;
    }

    @Override
    public OutputStream getRequestEntityStream() {
        return getRequestStream();
    }

    @Override
    public OutputStream getRequestHeadStream() {
        return getRequestStream();
    }

    /**
     * Returns the request entity stream if it exists.
     *
     * @return The request entity stream if it exists.
     */
    public OutputStream getRequestStream() {
        try {
            return getConnection().getOutputStream();
        } catch (IOException ioe) {
            return null;
        }
    }

    @Override
    public ReadableByteChannel getResponseEntityChannel(long size) {
        return null;
    }

    @Override
    public InputStream getResponseEntityStream(long size) {
        InputStream result = null;

        try {
            result = getConnection().getInputStream();
        } catch (IOException ioe) {
            result = getConnection().getErrorStream();
        }

        if (result == null) {
            // Maybe an error stream is available instead
            result = getConnection().getErrorStream();
        }

        return result;
    }

    /**
     * Returns the modifiable list of response headers.
     *
     * @return The modifiable list of response headers.
     */
    @Override
    public Series<Parameter> getResponseHeaders() {
        Series<Parameter> result = super.getResponseHeaders();

        if (!this.responseHeadersAdded) {
            // Read the response headers
            int i = 1;
            String headerName = getConnection().getHeaderFieldKey(i);
            String headerValue = getConnection().getHeaderField(i);
            while (headerName != null) {
                result.add(headerName, headerValue);
                i++;
                if (Edition.CURRENT != Edition.GAE) {
                    headerName = getConnection().getHeaderFieldKey(i);
                    headerValue = getConnection().getHeaderField(i);
                } else {
                    try {
                        headerName = getConnection().getHeaderFieldKey(i);
                        headerValue = getConnection().getHeaderField(i);
                    } catch (java.util.NoSuchElementException e) {
                        headerName = null;
                    }
                }
            }

            this.responseHeadersAdded = true;
        }

        return result;
    }

    /**
     * Returns the response address.<br>
     * Corresponds to the IP address of the responding server.
     *
     * @return The response address.
     */
    @Override
    public String getServerAddress() {
        return getConnection().getURL().getHost();
    }

    /**
     * Returns the response status code.
     *
     * @return The response status code.
     * @throws IOException
     * @throws IOException
     */
    @Override
    public int getStatusCode() throws IOException {
        return getConnection().getResponseCode();
    }

    /**
     * Sends the request to the client. Commits the request line, headers and
     * optional entity and send them over the network.
     *
     * @param request
     *            The high-level request.
     * @return The result status.
     */
    @Override
    public Status sendRequest(Request request) {
        Status result = null;

        try {
            if (request.isEntityAvailable()) {
                Representation entity = request.getEntity();

                // These properties can only be used with Java 1.5 and upper
                // releases
                int majorVersionNumber = SystemUtils.getJavaMajorVersion();
                int minorVersionNumber = SystemUtils.getJavaMinorVersion();
                if ((majorVersionNumber > 1)
                        || ((majorVersionNumber == 1) && (minorVersionNumber >= 5))) {
                    // Adjust the streaming mode
                    if (entity.getSize() != -1) {
                        // The size of the entity is known in advance
                        getConnection().setFixedLengthStreamingMode(
                                (int) entity.getSize());
                    } else {
                        // The size of the entity is not known in advance
                        if (getHelper().getChunkLength() >= 0) {
                            // Use chunked encoding
                            getConnection().setChunkedStreamingMode(
                                    getHelper().getChunkLength());
                        } else {
                            // Use entity buffering to determine the content
                            // length
                        }
                    }
                }
            }

            // Set the request method
            getConnection().setRequestMethod(getMethod());

            // Set the request headers
            for (Parameter header : getRequestHeaders()) {
                getConnection().addRequestProperty(header.getName(),
                        header.getValue());
            }

            if ((Edition.CURRENT == Edition.GAE)
                    && (request.getProtocol() == Protocol.SDC)) {
                // This is to ensure portable code with other Restlet editions.
                // that uses the proxy authorization header to transmit SDC
                // security parameters (not required on GAE).
                getConnection().getRequestProperties().remove(
                        HeaderConstants.HEADER_PROXY_AUTHORIZATION);
                getConnection().setRequestProperty("use_intranet", "true");
            }

            // Ensure that the connection is active
            getConnection().connect();

            // Send the optional entity
            result = super.sendRequest(request);
        } catch (ConnectException ce) {
            getHelper()
                    .getLogger()
                    .log(Level.FINE,
                            "An error occurred during the connection to the remote HTTP server.",
                            ce);
            result = new Status(Status.CONNECTOR_ERROR_CONNECTION, ce);
        } catch (SocketTimeoutException ste) {
            getHelper()
                    .getLogger()
                    .log(Level.FINE,
                            "An timeout error occurred during the communication with the remote HTTP server.",
                            ste);
            result = new Status(Status.CONNECTOR_ERROR_COMMUNICATION, ste);
        } catch (FileNotFoundException fnfe) {
            getHelper()
                    .getLogger()
                    .log(Level.FINE,
                            "An unexpected error occurred during the sending of the HTTP request.",
                            fnfe);
            result = new Status(Status.CONNECTOR_ERROR_INTERNAL, fnfe);
        } catch (IOException ioe) {
            getHelper()
                    .getLogger()
                    .log(Level.FINE,
                            "An error occurred during the communication with the remote HTTP server.",
                            ioe);
            result = new Status(Status.CONNECTOR_ERROR_COMMUNICATION, ioe);
        } catch (Exception e) {
            getHelper()
                    .getLogger()
                    .log(Level.FINE,
                            "An unexpected error occurred during the sending of the HTTP request.",
                            e);
            result = new Status(Status.CONNECTOR_ERROR_INTERNAL, e);
        }

        return result;
    }

    @Override
    public void sendRequest(Request request, Response response, Uniform callback)
            throws Exception {
        // Send the request
        sendRequest(request);

        if (request.getOnSent() != null) {
            request.getOnSent().handle(request, response);
        }

        if (callback != null) {
            // Transmit to the callback, if any.
            callback.handle(request, response);
        }
    }

}
TOP

Related Classes of org.restlet.ext.net.internal.HttpUrlConnectionCall

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.