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

org.glassfish.jersey.client.HttpUrlConnectorProvider Maven / Gradle / Ivy

There is a newer version: 8.16.0
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2013-2014 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * http://glassfish.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package org.glassfish.jersey.client;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.logging.Logger;

import javax.ws.rs.client.Client;
import javax.ws.rs.core.Configuration;

import org.glassfish.jersey.client.internal.LocalizationMessages;
import org.glassfish.jersey.client.spi.Connector;
import org.glassfish.jersey.client.spi.ConnectorProvider;

/**
 * Default Jersey client {@link org.glassfish.jersey.client.spi.Connector connector} provider
 * that provides connector instances which delegate HTTP requests to {@link java.net.HttpURLConnection}
 * for processing.
 * 

* The provided connector instances override default behaviour of the property * {@link ClientProperties#REQUEST_ENTITY_PROCESSING} and use {@link RequestEntityProcessing#BUFFERED} * request entity processing by default. *

*

* Due to a bug in the chunked transport coding support of {@code HttpURLConnection} that causes * requests to fail unpredictably, this connector provider allows to configure the provided connector * instances to use {@code HttpURLConnection}'s fixed-length streaming mode as a workaround. This * workaround can be enabled via {@link #useFixedLengthStreaming()} method or via * {@link #USE_FIXED_LENGTH_STREAMING} Jersey client configuration property. *

* * @author Marek Potociar (marek.potociar at oracle.com) */ public class HttpUrlConnectorProvider implements ConnectorProvider { /** * If {@code true}, the {@link HttpUrlConnector} (if used) will assume the content length * from the value of {@value javax.ws.rs.core.HttpHeaders#CONTENT_LENGTH} request * header (if present). *

* When this property is enabled and the request has a valid non-zero content length * value specified in its {@value javax.ws.rs.core.HttpHeaders#CONTENT_LENGTH} request * header, that this value will be used as an input to the * {@link java.net.HttpURLConnection#setFixedLengthStreamingMode(int)} method call * invoked on the underlying {@link java.net.HttpURLConnection connection}. * This will also suppress the entity buffering in the @{code HttpURLConnection}, * which is undesirable in certain scenarios, e.g. when streaming large entities. *

*

* Note that the content length value defined in the request header must exactly match * the real size of the entity. If the {@link javax.ws.rs.core.HttpHeaders#CONTENT_LENGTH} header * is explicitly specified in a request, this property will be ignored and the * request entity will be still buffered by the underlying @{code HttpURLConnection} infrastructure. *

*

* This property also overrides the behaviour enabled by the * {@link org.glassfish.jersey.client.ClientProperties#CHUNKED_ENCODING_SIZE} property. * Chunked encoding will only be used, if the size is not specified in the header of the request. *

*

* Note that this property only applies to client run-times that are configured to use the default * {@link HttpUrlConnector} as the client connector. The property is ignored by other connectors. *

*

* The default value is {@code false}. *

*

* The name of the configuration property is {@value}. *

* * @since 2.5 */ public static final String USE_FIXED_LENGTH_STREAMING = "jersey.config.client.httpUrlConnector.useFixedLengthStreaming"; /** * A value of {@code true} declares that the client will try to set * unsupported HTTP method to {@link java.net.HttpURLConnection} via * reflection. *

* NOTE: Enabling this property may cause security related warnings/errors * and it may break when other JDK implementation is used. Use only * when you know what you are doing. *

*

The value MUST be an instance of {@link java.lang.Boolean}.

*

The default value is {@code false}.

*

The name of the configuration property is {@value}.

*/ public static final String SET_METHOD_WORKAROUND = "jersey.config.client.httpUrlConnection.setMethodWorkaround"; /** * Default chunk size in HTTP chunk-encoded messages. */ private static final int DEFAULT_HTTP_CHUNK_SIZE = 4096; /** * Default connection factory to be used. */ private static final ConnectionFactory DEFAULT_CONNECTION_FACTORY = new DefaultConnectionFactory(); private static final Logger LOGGER = Logger.getLogger(HttpUrlConnectorProvider.class.getName()); private ConnectionFactory connectionFactory; private int chunkSize; private boolean useFixedLengthStreaming; private boolean useSetMethodWorkaround; /** * Create new {@link java.net.HttpURLConnection}-based Jersey client connector provider. */ public HttpUrlConnectorProvider() { this.connectionFactory = DEFAULT_CONNECTION_FACTORY; this.chunkSize = DEFAULT_HTTP_CHUNK_SIZE; this.useFixedLengthStreaming = false; this.useSetMethodWorkaround = false; } /** * Set a custom {@link java.net.HttpURLConnection} factory. * * @param connectionFactory custom HTTP URL connection factory. Must not be {@code null}. * @return updated connector provider instance. * @throws java.lang.NullPointerException in case the supplied connectionFactory is {@code null}. */ public HttpUrlConnectorProvider connectionFactory(final ConnectionFactory connectionFactory) { if (connectionFactory == null) { throw new NullPointerException(LocalizationMessages.NULL_INPUT_PARAMETER("connectionFactory")); } this.connectionFactory = connectionFactory; return this; } /** * Set chunk size for requests transferred using a * HTTP chunked transfer coding. * * If no value is set, the default chunk size of 4096 bytes will be used. *

* Note that this programmatically set value can be overridden by * setting the {@link org.glassfish.jersey.client.ClientProperties#CHUNKED_ENCODING_SIZE} property * specified in the Jersey client instance configuration. *

* * @param chunkSize chunked transfer coding chunk size to be used. * @return updated connector provider instance. * @throws java.lang.IllegalArgumentException in case the specified chunk size is negative. */ public HttpUrlConnectorProvider chunkSize(final int chunkSize) { if (chunkSize < 0) { throw new IllegalArgumentException(LocalizationMessages.NEGATIVE_INPUT_PARAMETER("chunkSize")); } this.chunkSize = chunkSize; return this; } /** * Instruct the provided connectors to use the {@link java.net.HttpURLConnection#setFixedLengthStreamingMode(int) * fixed-length streaming mode} on the underlying HTTP URL connection instance when sending requests. * See {@link #USE_FIXED_LENGTH_STREAMING} property documentation for more details. *

* Note that this programmatically set value can be overridden by * setting the {@code USE_FIXED_LENGTH_STREAMING} property specified in the Jersey client instance configuration. *

* * @return updated connector provider instance. */ public HttpUrlConnectorProvider useFixedLengthStreaming() { this.useFixedLengthStreaming = true; return this; } /** * Instruct the provided connectors to use reflection when setting the * HTTP method value.See {@link #SET_METHOD_WORKAROUND} property documentation for more details. *

* Note that this programmatically set value can be overridden by * setting the {@code SET_METHOD_WORKAROUND} property specified in the Jersey client instance configuration * or in the request properties. *

* * @return updated connector provider instance. */ public HttpUrlConnectorProvider useSetMethodWorkaround() { this.useSetMethodWorkaround = true; return this; } @Override public Connector getConnector(final Client client, final Configuration config) { final Map properties = config.getProperties(); int computedChunkSize = ClientProperties.getValue(properties, ClientProperties.CHUNKED_ENCODING_SIZE, chunkSize, Integer.class); if (computedChunkSize < 0) { LOGGER.warning(LocalizationMessages.NEGATIVE_CHUNK_SIZE(computedChunkSize, chunkSize)); computedChunkSize = chunkSize; } final boolean computedUseFixedLengthStreaming = ClientProperties.getValue(properties, USE_FIXED_LENGTH_STREAMING, useFixedLengthStreaming, Boolean.class); final boolean computedUseSetMethodWorkaround = ClientProperties.getValue(properties, SET_METHOD_WORKAROUND, useSetMethodWorkaround, Boolean.class); return new HttpUrlConnector( connectionFactory, computedChunkSize, computedUseFixedLengthStreaming, computedUseSetMethodWorkaround); } /** * A factory for {@link java.net.HttpURLConnection} instances. *

* A factory may be used to create a {@link java.net.HttpURLConnection} and configure * it in a custom manner that is not possible using the Client API. *

* A custom factory instance may be registered in the {@code HttpUrlConnectorProvider} instance * via {@link #connectionFactory(ConnectionFactory)} method. */ public interface ConnectionFactory { /** * Get a {@link java.net.HttpURLConnection} for a given URL. *

* Implementation of the method MUST be thread-safe and MUST ensure that * a dedicated {@link java.net.HttpURLConnection} instance is returned for concurrent * requests. *

* * @param url the endpoint URL. * @return the {@link java.net.HttpURLConnection}. * @throws java.io.IOException in case the connection cannot be provided. */ public HttpURLConnection getConnection(URL url) throws IOException; } private static class DefaultConnectionFactory implements ConnectionFactory { @Override public HttpURLConnection getConnection(final URL url) throws IOException { return (HttpURLConnection) url.openConnection(); } } @Override public boolean equals(final Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } final HttpUrlConnectorProvider that = (HttpUrlConnectorProvider) o; if (chunkSize != that.chunkSize) { return false; } if (useFixedLengthStreaming != that.useFixedLengthStreaming) { return false; } return connectionFactory.equals(that.connectionFactory); } @Override public int hashCode() { int result = connectionFactory.hashCode(); result = 31 * result + chunkSize; result = 31 * result + (useFixedLengthStreaming ? 1 : 0); return result; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy