Skip to content

Commits on Source 28

......@@ -17,3 +17,4 @@ target
test-output
/META-INF/MANIFEST.MF
work
atlassian-ide-plugin.xml
Async Http Client
Copyright 2010 Ning Inc
-----------------
DESCRIPTION
-----------
Getting started: http://is.gd/kexrN (PDF)
http://is.gd/ja6My (HTML)
Getting started [HTML](http://sonatype.github.com/async-http-client/) [PDF](http://is.gd/kexrN)
Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and asynchronously process the HTTP responses. The Async HTTP Client library is simple to use. First, in order to add it to your Maven project, simply add this dependency:
<repository>
<id>Sonatype</id>
<name>Sonatype Release</name>
<url>http://oss.sonatype.org/content/repositories/releases </url>
</repository>
and then define the dependency as:
Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and asynchronously process the HTTP responses. The library also supports the WebSocket Protocol. The Async HTTP Client library is simple to use. First, in order to add it to your Maven project, simply add this dependency:
```xml
<dependency>
<groupId>com.ning</groupId>
<artifactId>async-http-client</artifactId>
<version>1.6.2</version>
<version>1.7.3</version>
</dependency>
```
You can also download the artifact
http://oss.sonatype.org/content/repositories/releases
[Maven Search](http://search.maven.org)
Then in your code you can simply do:
Then in your code you can simply do ([Javadoc](http://sonatype.github.com/async-http-client/apidocs/index.html))
```java
import com.ning.http.client.*;
import java.util.concurrent.Future;
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
Future<Response> f = asyncHttpClient.prepareGet("http://www.ning.com/ ").execute();
Response r = f.get();
```
You can also accomplish asynchronous operation without using a Future if you want to receive and process the response in your handler:
```java
import com.ning.http.client.*;
import java.util.concurrent.Future;
......@@ -55,14 +49,17 @@ You can also accomplish asynchronous operation without using a Future if you wan
// Something wrong happened.
}
});
```
You can also mix Future with AsyncHandler to only retrieve part of the asynchronous response
```java
import com.ning.http.client.*;
import java.util.concurrent.Future;
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
Future<Integer> f = asyncHttpClient.prepareGet("http://www.ning.com/ ").execute(new AsyncCompletionHandler<Integer>(){
Future<Integer> f = asyncHttpClient.prepareGet("http://www.ning.com/ ").execute(
new AsyncCompletionHandler<Integer>(){
@Override
public Integer onCompleted(Response response) throws Exception{
......@@ -77,9 +74,11 @@ You can also mix Future with AsyncHandler to only retrieve part of the asynchron
});
int statuѕCode = f.get();
```
You have full control on the Response life cycle, so you can decide at any moment to stop processing what the server is sending back:
```java
import com.ning.http.client.*;
import java.util.concurrent.Future;
......@@ -106,7 +105,7 @@ You can also mix Future with AsyncHandler to only retrieve part of the asynchron
@Override
public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception {
builder.append(new String(bodyPart.getBodyPartBytes()));
return STATE.CONTINU
return STATE.CONTINUE
}
@Override
......@@ -122,16 +121,54 @@ You can also mix Future with AsyncHandler to only retrieve part of the asynchron
});
String bodyResponse = f.get();
```
Finally, you can also configure the AsyncHttpClient via it's AsyncHttpClientConfig object:
AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder().setProxyServer(new ProxyServer("127.0.0.1", 38080)).build();
```java
AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder()
S.setProxyServer(new ProxyServer("127.0.0.1", 38080)).build();
AsyncHttpClient c = new AsyncHttpClient(cf);
```
Async Http Client also support WebSocket by simply doing:
```java
WebSocket websocket = c.prepareGet(getTargetUrl())
.execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(
new WebSocketTextListener() {
@Override
public void onMessage(String message) {
}
@Override
public void onOpen(WebSocket websocket) {
websocket.sendTextMessage("...").sendBinaryMessage("...");
}
@Override
public void onClose(.WebSocket websocket) {
latch.countDown();
}
The library uses Java non blocking I/O for supporting asynchronous operations. The default asynchronous provider is build on top of Netty (http://www.jboss.org/netty), the Java NIO Client Server Socket Framework from JBoss, but the library exposes a configurable provider SPI which allows to easily plug in other frameworks.
@Override
public void onError(Throwable t) {
}
}).build()).get();
```
The library uses Java non blocking I/O for supporting asynchronous operations. The default asynchronous provider is build on top of [Netty](http://www.jboss.org/netty), but the library exposes a configurable provider SPI which allows to easily plug in other frameworks like [Grizzly](http://grizzly.java.net)
```java
AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().build();
AsyncHttpClient client = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config);
```
Keep up to date on the library development by joining the Asynchronous HTTP Client discussion group
http://groups.google.com/group/asynchttpclient
[Google Group](http://groups.google.com/group/asynchttpclient)
or follow us on [Twitter](http://twitter.com/jfarcand)
......@@ -9,22 +9,31 @@
<groupId>com.ning</groupId>
<artifactId>async-http-client</artifactId>
<name>Asynchronous Http Client</name>
<version>1.6.5</version>
<version>1.8.2</version>
<packaging>jar</packaging>
<description>
Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and
asynchronously process the HTTP responses.
</description>
<url>http://github.com/sonatype/async-http-client</url>
<url>http://github.com/AsyncHttpClient/async-http-client</url>
<scm>
<connection>scm:git:git@github.com:sonatype/async-http-client.git</connection>
<url>https://github.com/sonatype/async-http-client</url>
<developerConnection>scm:git:git@github.com:sonatype/async-http-client.git</developerConnection>
<connection>scm:git:git@github.com:AsyncHttpClient/async-http-client.git</connection>
<url>https://github.com/AsyncHttpClient/async-http-client</url>
<developerConnection>scm:git:git@github.com:AsyncHttpClient/async-http-client.git</developerConnection>
</scm>
<issueManagement>
<system>jira</system>
<url>https://issues.sonatype.org/browse/AHC</url>
</issueManagement>
<mailingLists>
<mailingList>
<name>asynchttpclient</name>
<archive>http://groups.google.com/group/asynchttpclient/topics</archive>
<subscribe>http://groups.google.com/group/asynchttpclient/subscribe</subscribe>
<unsubscribe>http://groups.google.com/group/asynchttpclient/subscribe</unsubscribe>
<post>asynchttpclient@googlegroups.com</post>
</mailingList>
</mailingLists>
<prerequisites>
<maven>2.0.9</maven>
......@@ -49,7 +58,18 @@
<id>neotyk</id>
<name>Hubert Iwaniuk</name>
</developer>
<developer>
<id>slandelle</id>
<name>Stephane Landelle</name>
<email>slandelle@excilys.com</email>
</developer>
</developers>
<contributors>
<contributor>
<name>Simone Tripodi</name>
<email>simonetripodi@apache.org</email>
</contributor>
</contributors>
<licenses>
<license>
<name>Apache License 2.0</name>
......@@ -59,40 +79,29 @@
</licenses>
<dependencies>
<dependency>
<groupId>org.jboss.netty</groupId>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
<version>3.2.5.Final</version>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
<version>3.9.0.Final</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.2</version>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>11.0.2</version>
<optional>true</optional>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.26</version>
<version>1.0.13</version>
<scope>test</scope>
</dependency>
<dependency>
......@@ -111,25 +120,31 @@
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>7.1.4.v20100610</version>
<version>8.1.1.v20120215</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>7.1.4.v20100610</version>
<version>8.1.1.v20120215</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-websocket</artifactId>
<version>8.1.1.v20120215</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<version>7.1.4.v20100610</version>
<version>8.1.1.v20120215</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
<version>7.1.4.v20100610</version>
<version>8.1.1.v20120215</version>
<scope>test</scope>
</dependency>
<dependency>
......@@ -192,9 +207,49 @@
<artifactId>wagon-ssh-external</artifactId>
<version>1.0-beta-6</version>
</extension>
<extension>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-provider-gitexe</artifactId>
<version>1.6</version>
</extension>
<extension>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-manager-plexus</artifactId>
<version>1.6</version>
</extension>
<extension>
<groupId>org.kathrynhuxtable.maven.wagon</groupId>
<artifactId>wagon-gitsite</artifactId>
<version>0.3.1</version>
</extension>
</extensions>
<defaultGoal>install</defaultGoal>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>${source.property}</source>
<target>${target.property}</target>
<maxmem>1024m</maxmem>
<excludes>
<exclude>${compiler.exclude}</exclude>
</excludes>
<testExcludes>
<testExclude>${test.compiler.exclude}</testExclude>
</testExcludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire.version}</version>
<configuration>
<!--<argLine>-Dorg.jboss.netty.tryUnsafe=true</argLine>-->
<redirectTestOutputToFile>${surefire.redirectTestOutputToFile}</redirectTestOutputToFile>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>
......@@ -219,7 +274,7 @@
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.0.1</version>
<version>2.3.4</version>
<extensions>true</extensions>
<configuration>
<manifestLocation>META-INF</manifestLocation>
......@@ -271,17 +326,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
<encoding>UTF-8</encoding>
<maxmem>1024m</maxmem>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
......@@ -321,14 +365,24 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.7</version>
<version>2.8.1</version>
<configuration>
<aggregate>true</aggregate>
<source>1.6</source>
<encoding>UTF-8</encoding>
<maxmemory>1g</maxmemory>
<links>
<link>http://java.sun.com/javase/6/docs/api/</link>
</links>
<excludePackageNames>${javadoc.package.exclude}</excludePackageNames>
</configuration>
<executions>
<execution>
......@@ -372,33 +426,80 @@
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>clirr-maven-plugin</artifactId>
<version>2.3</version>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.8.1</version>
<configuration>
<excludes>
<exclude>**/NettyAsyncHttpProvider$*</exclude>
<exclude>**/AsyncHandler$STATE</exclude>
<exclude>**/ProxyServer$Protocol</exclude>
<exclude>**/Realm$AuthScheme</exclude>
<exclude>**/SimpleAsyncHttpClient$ErrorDocumentBehaviour</exclude>
<exclude>**/SpnegoEngine</exclude>
</excludes>
<aggregate>true</aggregate>
<source>1.6</source>
<encoding>UTF-8</encoding>
<maxmemory>1g</maxmemory>
<links>
<link>http://java.sun.com/javase/6/docs/api/</link>
</links>
<excludePackageNames>${javadoc.package.exclude}</excludePackageNames>
<bootclasspath>${sun.boot.class.path}</bootclasspath>
<doclet>com.google.doclava.Doclava</doclet>
<useStandardDocletOptions>false</useStandardDocletOptions>
<additionalJOption>-J-Xmx1024m</additionalJOption>
<docletArtifact>
<groupId>com.google.doclava</groupId>
<artifactId>doclava</artifactId>
<version>1.0.3</version>
</docletArtifact>
<additionalparam>
-hdf project.name "${project.name} ${project.version}"
-d ${project.reporting.outputDirectory}/apidocs
</additionalparam>
</configuration>
<executions>
<execution>
<id>check-api-compat</id>
<phase>verify</phase>
<goals>
<goal>check-no-fork</goal>
</goals>
</execution>
</executions>
<reportSets>
<reportSet>
<id>default</id>
<reports>
<report>javadoc</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>${surefire.version}</version>
</plugin>
</plugins>
</build>
</reporting>
<profiles>
<profile>
<id>grizzly</id>
<activation>
<jdk>[1.6,)</jdk>
</activation>
<properties>
<compiler.exclude>asdfasfd/**</compiler.exclude>
<test.compiler.exclude>asdfasdf/**</test.compiler.exclude>
<javadoc.package.exclude>asdfasdf</javadoc.package.exclude>
<target.property>1.5</target.property>
</properties>
<dependencies>
<dependency>
<groupId>org.glassfish.grizzly</groupId>
<artifactId>grizzly-websockets</artifactId>
<version>2.3.11</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.glassfish.grizzly</groupId>
<artifactId>grizzly-http-server</artifactId>
<version>2.3.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
<profile>
<id>release-sign-artifacts</id>
<activation>
......@@ -434,6 +535,7 @@
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<groups>standalone</groups>
<redirectTestOutputToFile>${surefire.redirectTestOutputToFile}</redirectTestOutputToFile>
</configuration>
</plugin>
</plugins>
......@@ -448,26 +550,50 @@
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<groups>standalone, online</groups>
<redirectTestOutputToFile>${surefire.redirectTestOutputToFile}</redirectTestOutputToFile>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>test-output</id>
<properties>
<surefire.redirectTestOutputToFile>false</surefire.redirectTestOutputToFile>
</properties>
</profile>
</profiles>
<distributionManagement>
<repository>
<id>sonatype-nexus-staging</id>
<name>Sonatype Release</name>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2</url>
<url>http://oss.sonatype.org/service/local/staging/deploy/maven2</url>
</repository>
<snapshotRepository>
<id>sonatype-nexus-snapshots</id>
<name>sonatype-nexus-snapshots</name>
<url>${distMgmtSnapshotsUrl}</url>
</snapshotRepository>
<site>
<id>github</id>
<url>gitsite:git@github.com/AsyncHttpClient/async-http-client.git</url>
</site>
</distributionManagement>
<repositories>
<repository>
<id>maven.java.net</id>
<url>https://maven.java.net/content/repositories/releases</url>
</repository>
</repositories>
<properties>
<distMgmtSnapshotsUrl>https://oss.sonatype.org/content/repositories/snapshots</distMgmtSnapshotsUrl>
<distMgmtSnapshotsUrl>http://oss.sonatype.org/content/repositories/snapshots</distMgmtSnapshotsUrl>
<surefire.redirectTestOutputToFile>true</surefire.redirectTestOutputToFile>
<compiler.exclude>com/ning/http/client/providers/grizzly/*.java</compiler.exclude>
<test.compiler.exclude>com/ning/http/client/async/grizzly/*.java</test.compiler.exclude>
<javadoc.package.exclude>com.ning.http.client.providers.grizzly</javadoc.package.exclude>
<source.property>1.5</source.property>
<target.property>1.5</target.property>
<surefire.version>2.12</surefire.version>
</properties>
</project>
......@@ -73,7 +73,7 @@ public abstract class AsyncCompletionHandler<T> implements AsyncHandler<T>, Prog
/**
* Invoked once the HTTP response processing is finished.
* <p/>
*
* <p/>
* Gets always invoked as last callback method.
*
* @param response The {@link Response}
......@@ -104,6 +104,7 @@ public abstract class AsyncCompletionHandler<T> implements AsyncHandler<T>, Prog
/**
* Invoked when the I/O operation associated with the {@link Request} body as been progressed.
*
* @param amount The amount of bytes to transfer.
* @param current The amount of bytes transferred
* @param total The total number of bytes transferred
......
......@@ -25,11 +25,17 @@ import org.slf4j.LoggerFactory;
public class AsyncCompletionHandlerBase extends AsyncCompletionHandler<Response> {
private final Logger log = LoggerFactory.getLogger(AsyncCompletionHandlerBase.class);
/**
* {@inheritDoc}
*/
@Override
public Response onCompleted(Response response) throws Exception {
return response;
}
/**
* {@inheritDoc}
*/
/* @Override */
public void onThrowable(Throwable t) {
log.debug(t.getMessage(), t);
......
......@@ -25,19 +25,19 @@ package com.ning.http.client;
* <li>{@link #onBodyPartReceived(HttpResponseBodyPart)}, which could be invoked multiple times,</li>
* <li>{@link #onCompleted()}, once the response has been fully read.</li>
* </ol>
*
* <p/>
* Returning a {@link AsyncHandler.STATE#ABORT} from any of those callback methods will interrupt asynchronous response
* processing, after that only {@link #onCompleted()} is going to be called.
* <p/>
*
* <p/>
* AsyncHandler aren't thread safe, hence you should avoid re-using the same instance when doing concurrent requests.
* As an exmaple, the following may produce unexpected results:
* {@code
* <blockquote><pre>
* AsyncHandler ah = new AsyncHandler() {....};
* AsyncHttpClient client = new AsyncHttpClient();
* client.prepareGet("http://...").execute(ah);
* client.prepareGet("http://...").execute(ah);
* }
* </pre></blockquote>
* It is recommended to create a new instance instead.
*
* @param <T> Type of object returned by the {@link java.util.concurrent.Future#get}
......@@ -55,15 +55,14 @@ public interface AsyncHandler<T> {
*/
CONTINUE,
/**
* Pause the current processing.
* Upgrade the protocol.
*/
PAUSE
UPGRADE
}
/**
* Invoked when an unexpected exception occurs during the processing of the response. The exception may have been
* produced by implementation of onXXXReceived method invokation.
* produced by implementation of onXXXReceived method invocation.
*
* @param t a {@link Throwable}
*/
......@@ -71,33 +70,36 @@ public interface AsyncHandler<T> {
/**
* Invoked as soon as some response body part are received. Could be invoked many times.
*
* @param bodyPart response's body part.
* @throws Exception if something wrong happens
* @return a {@link STATE} telling to CONTINUE or ABORT the current processing.
* @throws Exception if something wrong happens
*/
STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception;
/**
* Invoked as soon as the HTTP status line has been received
*
* @param responseStatus the status code and test of the response
* @throws Exception if something wrong happens
* @return a {@link STATE} telling to CONTINUE or ABORT the current processing.
* @throws Exception if something wrong happens
*/
STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception;
/**
* Invoked as soon as the HTTP headers has been received. Can potentially be invoked more than once if a broken server
* sent trailling headers.
* sent trailing headers.
*
* @param headers the HTTP headers.
* @throws Exception if something wrong happens
* @return a {@link STATE} telling to CONTINUE or ABORT the current processing.
* @throws Exception if something wrong happens
*/
STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception;
/**
* Invoked once the HTTP response processing is finished.
* <p/>
*
* <p/>
* Gets always invoked as last callback method.
*
* @return T Value that will be returned by the associated {@link java.util.concurrent.Future}
......
/*
* Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the Apache License Version 2.0 is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
*/
package com.ning.http.client;
/**
* This interface hosts new low level callback methods on {@link AsyncHandler}.
* For now, those methods are in a dedicated interface in order not to break the existing API,
* but could be merged into one of the existing ones in AHC 2.
*
* More additional hooks might come, such as:
* <ul>
* <li>onConnected()</li>
* <li>onConnectionClosed()</li>
* <li>onBytesSent(long numberOfBytes)</li>
* <li>onBytesReceived(long numberOfBytes)</li>
* </ul>
*/
public interface AsyncHandlerExtensions {
/**
* Notify the callback when a request is being written on the wire.
* If the original request causes multiple requests to be sent, for example, because of authorization or retry,
* it will be notified multiple times.
* Currently only supported by the Netty provider.
*/
void onRequestSent();
/**
* Notify the callback every time a request is being retried.
*/
void onRetry();
}
......@@ -16,130 +16,135 @@
*/
package com.ning.http.client;
import com.ning.http.client.Request.EntityWriter;
import com.ning.http.client.filter.FilterContext;
import com.ning.http.client.filter.FilterException;
import com.ning.http.client.filter.RequestFilter;
import com.ning.http.client.resumable.ResumableAsyncHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ning.http.client.providers.jdk.JDKAsyncHttpProvider;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ning.http.client.Request.EntityWriter;
import com.ning.http.client.cookie.Cookie;
import com.ning.http.client.filter.FilterContext;
import com.ning.http.client.filter.FilterException;
import com.ning.http.client.filter.RequestFilter;
import com.ning.http.client.providers.jdk.JDKAsyncHttpProvider;
import com.ning.http.client.resumable.ResumableAsyncHandler;
/**
* This class support asynchronous and synchronous HTTP request.
*
* <p/>
* To execute synchronous HTTP request, you just need to do
* {@code
* <blockquote><pre>
* AsyncHttpClient c = new AsyncHttpClient();
* Future<Response> f = c.prepareGet("http://www.ning.com/").execute();
* }
*
* </pre></blockquote
* <p/>
* The code above will block until the response is fully received. To execute asynchronous HTTP request, you
* create an {@link AsyncHandler} or its abstract implementation, {@link com.ning.http.client.AsyncCompletionHandler}
*
* {@code
* <p/>
* <blockquote><pre>
* AsyncHttpClient c = new AsyncHttpClient();
* Future<Response> f = c.prepareGet("http://www.ning.com/").execute(new AsyncCompletionHandler<Response>() &#123;
*
* <p/>
* &#64;Override
* public Response onCompleted(Response response) throws IOException &#123;
* // Do something
* return response;
* &#125;
*
* <p/>
* &#64;Override
* public void onThrowable(Throwable t) &#123;
* &#125;
* &#125;);
* Response response = f.get();
*
* <p/>
* // We are just interested to retrieve the status code.
* Future<Integer> f = c.prepareGet("http://www.ning.com/").execute(new AsyncCompletionHandler<Integer>() &#123;
*
* <p/>
* &#64;Override
* public Integer onCompleted(Response response) throws IOException &#123;
* // Do something
* return response.getStatusCode();
* &#125;
*
* <p/>
* &#64;Override
* public void onThrowable(Throwable t) &#123;
* &#125;
* &#125;);
* Integer statusCode = f.get();
* }
* </pre></blockquote
* The {@link AsyncCompletionHandler#onCompleted(com.ning.http.client.Response)} will be invoked once the http response has been fully read, which include
* the http headers and the response body. Note that the entire response will be buffered in memory.
*
* <p/>
* You can also have more control about the how the response is asynchronously processed by using a {@link AsyncHandler}
* {@code
* <blockquote><pre>
* AsyncHttpClient c = new AsyncHttpClient();
* Future<String> f = c.prepareGet("http://www.ning.com/").execute(new AsyncHandler<String>() &#123;
* private StringBuilder builder = new StringBuilder();
*
* <p/>
* &#64;Override
* public STATE onStatusReceived(HttpResponseStatus s) throws Exception &#123;
* // return STATE.CONTINUE or STATE.ABORT
* return STATE.CONTINUE
* }
*
* <p/>
* &#64;Override
* public STATE onHeadersReceived(HttpResponseHeaders bodyPart) throws Exception &#123;
* // return STATE.CONTINUE or STATE.ABORT
* return STATE.CONTINUE
*
* <p/>
* }
* &#64;Override
*
* <p/>
* public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception &#123;
* builder.append(new String(bodyPart));
* // return STATE.CONTINUE or STATE.ABORT
* return STATE.CONTINUE
* &#125;
*
* <p/>
* &#64;Override
* public String onCompleted() throws Exception &#123;
* // Will be invoked once the response has been fully read or a ResponseComplete exception
* // has been thrown.
* return builder.toString();
* &#125;
*
* <p/>
* &#64;Override
* public void onThrowable(Throwable t) &#123;
* &#125;
* &#125;);
*
* <p/>
* String bodyResponse = f.get();
* }
* </pre></blockquote
* From any {@link HttpContent} sub classes, you can asynchronously process the response status,headers and body and decide when to
* stop the processing the response by throwing a new {link ResponseComplete} at any moment.
*
* <p/>
* This class can also be used without the need of {@link AsyncHandler}</p>
* {@code
* <blockquote><pre>
* AsyncHttpClient c = new AsyncHttpClient();
* Future<Response> f = c.prepareGet(TARGET_URL).execute();
* Response r = f.get();
* }
*
* </pre></blockquote>
* <p/>
* Finally, you can configure the AsyncHttpClient using an {@link AsyncHttpClientConfig} instance</p>
* {@code
* <blockquote><pre>
* AsyncHttpClient c = new AsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(...).build());
* Future<Response> f = c.prepareGet(TARGET_URL).execute();
* Response r = f.get();
* }
*
* </pre></blockquote>
* <p/>
* An instance of this class will cache every HTTP 1.1 connections and close them when the {@link AsyncHttpClientConfig#getIdleConnectionTimeoutInMs()}
* expires. This object can hold many persistent connections to different host.
*
*/
public class AsyncHttpClient {
public class AsyncHttpClient implements Closeable {
private final static String DEFAULT_PROVIDER = "com.ning.http.client.providers.netty.NettyAsyncHttpProvider";
private final AsyncHttpProvider httpProvider;
......@@ -165,6 +170,7 @@ public class AsyncHttpClient {
/**
* Create a new HTTP Asynchronous Client using an implementation of {@link AsyncHttpProvider} and
* the default {@link AsyncHttpClientConfig} configuration.
*
* @param provider a {@link AsyncHttpProvider}
*/
public AsyncHttpClient(AsyncHttpProvider provider) {
......@@ -174,6 +180,7 @@ public class AsyncHttpClient {
/**
* Create a new HTTP Asynchronous Client using a {@link AsyncHttpClientConfig} configuration and the
* {@link #DEFAULT_PROVIDER}
*
* @param config a {@link AsyncHttpClientConfig}
*/
public AsyncHttpClient(AsyncHttpClientConfig config) {
......@@ -183,6 +190,7 @@ public class AsyncHttpClient {
/**
* Create a new HTTP Asynchronous Client using a {@link AsyncHttpClientConfig} configuration and
* and a {@link AsyncHttpProvider}.
*
* @param config a {@link AsyncHttpClientConfig}
* @param httpProvider a {@link AsyncHttpProvider}
*/
......@@ -194,6 +202,7 @@ public class AsyncHttpClient {
/**
* Create a new HTTP Asynchronous Client using a {@link AsyncHttpClientConfig} configuration and
* and a AsyncHttpProvider class' name.
*
* @param config a {@link AsyncHttpClientConfig}
* @param providerClass a {@link AsyncHttpProvider}
*/
......@@ -215,8 +224,8 @@ public class AsyncHttpClient {
*/
protected String baseURL;
private BoundRequestBuilder(String reqType) {
super(BoundRequestBuilder.class, reqType);
private BoundRequestBuilder(String reqType, boolean useRawUrl) {
super(BoundRequestBuilder.class, reqType, useRawUrl);
}
private BoundRequestBuilder(Request prototype) {
......@@ -272,7 +281,7 @@ public class AsyncHttpClient {
if (i >= 0) {
url = url.substring(0, i);
}
signatureCalculator.calculateAndAddSignature(baseURL, request, this);
signatureCalculator.calculateAndAddSignature(url, request, this);
}
return super.build();
}
......@@ -347,6 +356,7 @@ public class AsyncHttpClient {
/**
* Return the asynchronous {@link com.ning.http.client.AsyncHttpProvider}
*
* @return an {@link com.ning.http.client.AsyncHttpProvider}
*/
public AsyncHttpProvider getProvider() {
......@@ -357,15 +367,34 @@ public class AsyncHttpClient {
* Close the underlying connections.
*/
public void close() {
if (isClosed.compareAndSet(false, true)) {
httpProvider.close();
isClosed.set(true);
}
}
/**
* Asynchronous close the {@link AsyncHttpProvider} by spawning a thread and avoid blocking.
*/
public void closeAsynchronously() {
final ExecutorService e = Executors.newSingleThreadExecutor();
e.submit(new Runnable() {
public void run() {
try {
close();
} catch (Throwable t) {
logger.warn("", t);
} finally {
e.shutdown();
}
}
});
}
@Override
protected void finalize() throws Throwable {
try {
if (!isClosed.get()) {
logger.warn("AsyncHttpClient.close() hasn't been invoked, which may produce file descriptor leaks");
logger.debug("AsyncHttpClient.close() hasn't been invoked, which may produce file descriptor leaks");
}
} finally {
super.finalize();
......@@ -374,6 +403,7 @@ public class AsyncHttpClient {
/**
* Return true if closed
*
* @return true if closed
*/
public boolean isClosed() {
......@@ -382,6 +412,7 @@ public class AsyncHttpClient {
/**
* Return the {@link com.ning.http.client.AsyncHttpClientConfig}
*
* @return {@link com.ning.http.client.AsyncHttpClientConfig}
*/
public AsyncHttpClientConfig getConfig() {
......@@ -398,6 +429,7 @@ public class AsyncHttpClient {
/**
* Prepare an HTTP client GET request.
*
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
......@@ -407,6 +439,7 @@ public class AsyncHttpClient {
/**
* Prepare an HTTP client CONNECT request.
*
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
......@@ -416,6 +449,7 @@ public class AsyncHttpClient {
/**
* Prepare an HTTP client OPTIONS request.
*
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
......@@ -425,6 +459,7 @@ public class AsyncHttpClient {
/**
* Prepare an HTTP client HEAD request.
*
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
......@@ -434,6 +469,7 @@ public class AsyncHttpClient {
/**
* Prepare an HTTP client POST request.
*
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
......@@ -443,6 +479,7 @@ public class AsyncHttpClient {
/**
* Prepare an HTTP client PUT request.
*
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
......@@ -452,6 +489,7 @@ public class AsyncHttpClient {
/**
* Prepare an HTTP client DELETE request.
*
* @param url A well formed URL.
* @return {@link RequestBuilder}
*/
......@@ -461,6 +499,7 @@ public class AsyncHttpClient {
/**
* Construct a {@link RequestBuilder} using a {@link Request}
*
* @param request a {@link Request}
* @return {@link RequestBuilder}
*/
......@@ -470,6 +509,7 @@ public class AsyncHttpClient {
/**
* Execute an HTTP request.
*
* @param request {@link Request}
* @param handler an instance of {@link AsyncHandler}
* @param <T> Type of the value that will be returned by the associated {@link java.util.concurrent.Future}
......@@ -486,6 +526,7 @@ public class AsyncHttpClient {
/**
* Execute an HTTP request.
*
* @param request {@link Request}
* @return a {@link Future} of type Response
* @throws IOException
......@@ -517,7 +558,7 @@ public class AsyncHttpClient {
}
Request request = fc.getRequest();
if (ResumableAsyncHandler.class.isAssignableFrom(fc.getAsyncHandler().getClass())) {
if (fc.getAsyncHandler() instanceof ResumableAsyncHandler) {
request = ResumableAsyncHandler.class.cast(fc.getAsyncHandler()).adjustRequestRange(request);
}
......@@ -539,6 +580,16 @@ public class AsyncHttpClient {
new Class[]{AsyncHttpClientConfig.class}).newInstance(new Object[]{config});
} catch (Throwable t) {
if (t instanceof InvocationTargetException) {
final InvocationTargetException ite = (InvocationTargetException) t;
if (logger.isErrorEnabled()) {
logger.error(
"Unable to instantiate provider {}. Trying other providers.",
className);
logger.error(ite.getCause().toString(), ite.getCause());
}
}
// Let's try with another classloader
try {
Class<AsyncHttpProvider> providerClass = (Class<AsyncHttpProvider>)
......@@ -557,7 +608,7 @@ public class AsyncHttpClient {
}
protected BoundRequestBuilder requestBuilder(String reqType, String url) {
return new BoundRequestBuilder(reqType).setUrl(url).setSignatureCalculator(signatureCalculator);
return new BoundRequestBuilder(reqType, config.isUseRawUrl()).setUrl(url).setSignatureCalculator(signatureCalculator);
}
protected BoundRequestBuilder requestBuilder(Request prototype) {
......
/*
* Copyright (c) 2010-2011 Sonatype, Inc. All rights reserved.
* Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
......@@ -23,7 +23,6 @@ import javax.net.ssl.SSLSession;
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
/**
......@@ -48,15 +47,20 @@ public class AsyncHttpClientConfigBean extends AsyncHttpClientConfig {
maxConnectionPerHost = Integer.getInteger(ASYNC_CLIENT + "defaultMaxConnectionsPerHost", -1);
connectionTimeOutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultConnectionTimeoutInMS", 60 * 1000);
idleConnectionInPoolTimeoutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultIdleConnectionInPoolTimeoutInMS", 60 * 1000);
idleConnectionTimeoutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultIdleConnectionTimeoutInMS", 60 * 1000);
requestTimeoutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultRequestTimeoutInMS", 60 * 1000);
redirectEnabled = Boolean.getBoolean(ASYNC_CLIENT + "defaultRedirectsEnabled");
maxDefaultRedirects = Integer.getInteger(ASYNC_CLIENT + "defaultMaxRedirects", 5);
compressionEnabled = Boolean.getBoolean(ASYNC_CLIENT + "compressionEnabled");
userAgent = System.getProperty(ASYNC_CLIENT + "userAgent", "NING/1.0");
ioThreadMultiplier = Integer.getInteger(ASYNC_CLIENT + "ioThreadMultiplier", 2);
boolean useProxySelector = Boolean.getBoolean(ASYNC_CLIENT + "useProxySelector");
boolean useProxyProperties = Boolean.getBoolean(ASYNC_CLIENT + "useProxyProperties");
if (useProxyProperties) {
proxyServer = ProxyUtils.createProxy(System.getProperties());
if (useProxySelector) {
proxyServerSelector = ProxyUtils.getJdkDefaultProxyServerSelector();
} else if (useProxyProperties) {
proxyServerSelector = ProxyUtils.createProxyServerSelector(System.getProperties());
}
allowPoolingConnection = true;
......@@ -74,13 +78,6 @@ public class AsyncHttpClientConfigBean extends AsyncHttpClientConfig {
}
void configureExecutors() {
reaper = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "AsyncHttpClient-Reaper");
t.setDaemon(true);
return t;
}
});
applicationThreadPool = Executors.newCachedThreadPool(new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "AsyncHttpClient-Callback");
......@@ -110,6 +107,11 @@ public class AsyncHttpClientConfigBean extends AsyncHttpClientConfig {
return this;
}
public AsyncHttpClientConfigBean setIdleConnectionTimeoutInMs(int idleConnectionTimeoutInMs) {
this.idleConnectionTimeoutInMs = idleConnectionTimeoutInMs;
return this;
}
public AsyncHttpClientConfigBean setRequestTimeoutInMs(int requestTimeoutInMs) {
this.requestTimeoutInMs = requestTimeoutInMs;
return this;
......@@ -140,14 +142,6 @@ public class AsyncHttpClientConfigBean extends AsyncHttpClientConfig {
return this;
}
public AsyncHttpClientConfigBean setReaper(ScheduledExecutorService reaper) {
if (this.reaper != null) {
this.reaper.shutdownNow();
}
this.reaper = reaper;
return this;
}
public AsyncHttpClientConfigBean setApplicationThreadPool(ExecutorService applicationThreadPool) {
if (this.applicationThreadPool != null) {
this.applicationThreadPool.shutdownNow();
......@@ -157,7 +151,12 @@ public class AsyncHttpClientConfigBean extends AsyncHttpClientConfig {
}
public AsyncHttpClientConfigBean setProxyServer(ProxyServer proxyServer) {
this.proxyServer = proxyServer;
this.proxyServerSelector = ProxyUtils.createProxyServerSelector(proxyServer);
return this;
}
public AsyncHttpClientConfigBean setProxyServerSelector(ProxyServerSelector proxyServerSelector) {
this.proxyServerSelector = proxyServerSelector;
return this;
}
......
......@@ -16,7 +16,7 @@
package com.ning.http.client;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
/**
* Interface to be used when implementing custom asynchronous I/O HTTP client.
......@@ -40,6 +40,7 @@ public interface AsyncHttpProvider {
/**
* Prepare a {@link Response}
*
* @param status {@link HttpResponseStatus}
* @param headers {@link HttpResponseHeaders}
* @param bodyParts list of {@link HttpResponseBodyPart}
......@@ -47,6 +48,6 @@ public interface AsyncHttpProvider {
*/
public Response prepareResponse(HttpResponseStatus status,
HttpResponseHeaders headers,
Collection<HttpResponseBodyPart> bodyParts);
List<HttpResponseBodyPart> bodyParts);
}
/*
* Copyright (c) 2010-2011 Sonatype, Inc. All rights reserved.
* Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
......
/*
* Copyright (c) 2010-2011 Sonatype, Inc. All rights reserved.
* Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
......@@ -36,15 +35,13 @@ public interface Body {
* @return The non-negative number of bytes actually read or {@code -1} if the body has been read completely.
* @throws IOException If the chunk could not be read.
*/
long read(ByteBuffer buffer)
throws IOException;
long read(ByteBuffer buffer) throws IOException;
/**
* Releases any resources associated with this body.
*
* @throws IOException
*/
void close()
throws IOException;
void close() throws IOException;
}
/*
* Copyright (c) 2010-2011 Sonatype, Inc. All rights reserved.
* Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
......@@ -31,6 +31,7 @@ public interface BodyConsumer {
/**
* Invoked when all the response bytes has been processed.
*
* @throws IOException
*/
void close() throws IOException;
......
/*
* Copyright (c) 2010-2011 Sonatype, Inc. All rights reserved.
* Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
......@@ -12,6 +12,8 @@
*/
package com.ning.http.client;
import com.ning.http.client.Response.ResponseBuilder;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
......@@ -21,13 +23,11 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
import com.ning.http.client.Response.ResponseBuilder;
/**
* An AsyncHandler that returns Response (without body, so status code and
* headers only) as fast as possible for inspection, but leaves you the option
* to defer body consumption.
* <p>
* <p/>
* This class introduces new call: getResponse(), that blocks caller thread as
* long as headers are received, and return Response as soon as possible, but
* still pouring response body into supplied output stream. This handler is
......@@ -37,10 +37,10 @@ import com.ning.http.client.Response.ResponseBuilder;
* be GETted, but you need headers first, or you don't know yet (depending on
* some logic, maybe coming from headers) where to save the body, or you just
* want to leave body stream to some other component to consume it.
* <p>
* <p/>
* All these above means that this AsyncHandler needs a bit of different
* handling than "recommended" way. Some examples:
*
* <p/>
* <pre>
* FileOutputStream fos = ...
* BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(fos);
......@@ -55,7 +55,7 @@ import com.ning.http.client.Response.ResponseBuilder;
* // finally &quot;join&quot; the download
* fr.get();
* </pre>
*
* <p/>
* <pre>
* PipedOutputStream pout = new PipedOutputStream();
* BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(pout);
......@@ -72,7 +72,6 @@ import com.ning.http.client.Response.ResponseBuilder;
* ...
* }
* </pre>
*
*/
public class BodyDeferringAsyncHandler implements AsyncHandler<Response> {
private final ResponseBuilder responseBuilder = new ResponseBuilder();
......@@ -81,7 +80,7 @@ public class BodyDeferringAsyncHandler implements AsyncHandler<Response> {
private final OutputStream output;
private volatile boolean responseSet;
private boolean responseSet;
private volatile Response response;
......@@ -152,6 +151,12 @@ public class BodyDeferringAsyncHandler implements AsyncHandler<Response> {
}
public Response onCompleted() throws IOException {
if (!responseSet) {
response = responseBuilder.build();
responseSet = true;
}
// Counting down to handle error cases too.
// In "normal" cases, latch is already at 0 here
// But in other cases, for example when because of some error
......
/*
* Copyright (c) 2010-2011 Sonatype, Inc. All rights reserved.
* Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
......
......@@ -17,11 +17,11 @@
package com.ning.http.client;
public class ByteArrayPart implements Part {
private String name;
private String fileName;
private byte[] data;
private String mimeType;
private String charSet;
private final String name;
private final String fileName;
private final byte[] data;
private final String mimeType;
private final String charSet;
public ByteArrayPart(String name, String fileName, byte[] data, String mimeType, String charSet) {
this.name = name;
......@@ -31,6 +31,10 @@ public class ByteArrayPart implements Part {
this.charSet = charSet;
}
/**
* {@inheritDoc}
*/
/* @Override */
public String getName() {
return name;
}
......
/*
* Copyright 2010 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.ning.http.client;
import java.net.URI;
public interface ConnectionPoolKeyStrategy {
String getKey(URI uri);
}
\ No newline at end of file
......@@ -23,6 +23,7 @@ public interface ConnectionsPool<U, V> {
/**
* Add a connection tpo the pool
*
* @param uri a uri used to retrieve the cached connection
* @param connection an I/O connection
* @return true if added.
......@@ -31,6 +32,7 @@ public interface ConnectionsPool<U, V> {
/**
* Remove the connection associated with the uri.
*
* @param uri the uri used when invoking addConnection
* @return the connection associated with the uri
*/
......@@ -38,6 +40,7 @@ public interface ConnectionsPool<U, V> {
/**
* Remove all connections from the cache. A connection might have been associated with several uri.
*
* @param connection a connection
* @return the true if the connection has been removed
*/
......@@ -46,6 +49,7 @@ public interface ConnectionsPool<U, V> {
/**
* Return true if a connection can be cached. A implementation can decide based on some rules to allow caching
* Calling this method is equivalent of checking the returned value of {@link ConnectionsPool#offer(Object, Object)}
*
* @return true if a connection can be cached.
*/
public boolean canCacheConnection();
......
/*
* Copyright 2010 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
*/
package com.ning.http.client;
import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;
public class Cookie {
private final String domain;
private final String name;
private final String value;
private final String path;
private final int maxAge;
private final boolean secure;
private final int version;
private Set<Integer> ports = Collections.emptySet();
private Set<Integer> unmodifiablePorts = ports;
public Cookie(String domain, String name, String value, String path, int maxAge, boolean secure) {
this.domain = domain;
this.name = name;
this.value = value;
this.path = path;
this.maxAge = maxAge;
this.secure = secure;
this.version = 1;
}
public Cookie(String domain, String name, String value, String path, int maxAge, boolean secure, int version) {
this.domain = domain;
this.name = name;
this.value = value;
this.path = path;
this.maxAge = maxAge;
this.secure = secure;
this.version = version;
}
public String getDomain() {
return domain;
}
public String getName() {
return name == null ? "" : name;
}
public String getValue() {
return value == null ? "" : value;
}
public String getPath() {
return path;
}
public int getMaxAge() {
return maxAge;
}
public boolean isSecure() {
return secure;
}
public int getVersion() {
return version;
}
public Set<Integer> getPorts() {
if (unmodifiablePorts == null) {
unmodifiablePorts = Collections.unmodifiableSet(ports);
}
return unmodifiablePorts;
}
public void setPorts(int... ports) {
if (ports == null) {
throw new NullPointerException("ports");
}
int[] portsCopy = ports.clone();
if (portsCopy.length == 0) {
unmodifiablePorts = this.ports = Collections.emptySet();
} else {
Set<Integer> newPorts = new TreeSet<Integer>();
for (int p: portsCopy) {
if (p <= 0 || p > 65535) {
throw new IllegalArgumentException("port out of range: " + p);
}
newPorts.add(Integer.valueOf(p));
}
this.ports = newPorts;
unmodifiablePorts = null;
}
}
public void setPorts(Iterable<Integer> ports) {
Set<Integer> newPorts = new TreeSet<Integer>();
for (int p: ports) {
if (p <= 0 || p > 65535) {
throw new IllegalArgumentException("port out of range: " + p);
}
newPorts.add(Integer.valueOf(p));
}
if (newPorts.isEmpty()) {
unmodifiablePorts = this.ports = Collections.emptySet();
} else {
this.ports = newPorts;
unmodifiablePorts = null;
}
}
@Override
public String toString() {
return String.format("Cookie: domain=%s, name=%s, value=%s, path=%s, maxAge=%d, secure=%s",
domain, name, value, path, maxAge, secure);
}
}