From e3cdb72de7d479754edc7d4f6fd4bdfc9e8339ac Mon Sep 17 00:00:00 2001 From: Oleg Kalnichevski Date: Thu, 15 Mar 2018 11:54:11 +0100 Subject: [PATCH] Added examples of full-duplex HTTP/1.1 and HTTP/2 message exchanges --- .../AsyncClientFullDuplexExchange.java | 151 ++++++++++++++++++ .../AsyncClientHttp2FullDuplexExchange.java | 147 +++++++++++++++++ 2 files changed, 298 insertions(+) create mode 100644 httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientFullDuplexExchange.java create mode 100644 httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientHttp2FullDuplexExchange.java diff --git a/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientFullDuplexExchange.java b/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientFullDuplexExchange.java new file mode 100644 index 000000000..47e612daa --- /dev/null +++ b/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientFullDuplexExchange.java @@ -0,0 +1,151 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.hc.client5.http.examples; + +import java.io.IOException; +import java.net.URI; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.hc.client5.http.impl.async.HttpAsyncClients; +import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.EntityDetails; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.config.H1Config; +import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler; +import org.apache.hc.core5.http.nio.BasicRequestProducer; +import org.apache.hc.core5.http.nio.BasicResponseConsumer; +import org.apache.hc.core5.http.nio.CapacityChannel; +import org.apache.hc.core5.http.nio.DataStreamChannel; +import org.apache.hc.core5.http.nio.RequestChannel; +import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer; +import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer; +import org.apache.hc.core5.http2.HttpVersionPolicy; +import org.apache.hc.core5.http2.config.H2Config; +import org.apache.hc.core5.io.ShutdownType; +import org.apache.hc.core5.reactor.IOReactorConfig; +import org.apache.hc.core5.util.Timeout; + +/** + * This example demonstrates a full-duplex, streaming HTTP/1.1 message exchange. + */ +public class AsyncClientFullDuplexExchange { + + public static void main(final String[] args) throws Exception { + + final IOReactorConfig ioReactorConfig = IOReactorConfig.custom() + .setSoTimeout(Timeout.ofSeconds(5)) + .build(); + + final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal( + HttpVersionPolicy.NEGOTIATE, + H2Config.DEFAULT, + H1Config.DEFAULT, + ioReactorConfig); + + client.start(); + + final URI requestUri = new URI("http://httpbin.org/post"); + final BasicRequestProducer requestProducer = new BasicRequestProducer( + "POST", requestUri, new BasicAsyncEntityProducer("stuff", ContentType.TEXT_PLAIN)); + final BasicResponseConsumer responseConsumer = new BasicResponseConsumer<>( + new StringAsyncEntityConsumer()); + + final CountDownLatch latch = new CountDownLatch(1); + client.execute(new AsyncClientExchangeHandler() { + + @Override + public void releaseResources() { + requestProducer.releaseResources(); + responseConsumer.releaseResources(); + latch.countDown(); + } + + @Override + public void cancel() { + System.out.println(requestUri + " cancelled"); + } + + @Override + public void failed(final Exception cause) { + System.out.println(requestUri + "->" + cause); + } + + @Override + public void produceRequest(final RequestChannel channel) throws HttpException, IOException { + requestProducer.sendRequest(channel); + } + + @Override + public int available() { + return requestProducer.available(); + } + + @Override + public void produce(final DataStreamChannel channel) throws IOException { + requestProducer.produce(channel); + } + + @Override + public void consumeInformation(final HttpResponse response) throws HttpException, IOException { + System.out.println(requestUri + "->" + response.getCode()); + } + + @Override + public void consumeResponse(final HttpResponse response, final EntityDetails entityDetails) throws HttpException, IOException { + System.out.println(requestUri + "->" + response.getCode()); + responseConsumer.consumeResponse(response, entityDetails, null); + } + + @Override + public void updateCapacity(final CapacityChannel capacityChannel) throws IOException { + responseConsumer.updateCapacity(capacityChannel); + } + + @Override + public int consume(final ByteBuffer src) throws IOException { + return responseConsumer.consume(src); + } + + @Override + public void streamEnd(final List trailers) throws HttpException, IOException { + responseConsumer.streamEnd(trailers); + } + + }); + latch.await(1, TimeUnit.MINUTES); + + System.out.println("Shutting down"); + client.shutdown(ShutdownType.GRACEFUL); + } + +} diff --git a/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientHttp2FullDuplexExchange.java b/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientHttp2FullDuplexExchange.java new file mode 100644 index 000000000..b550f9d17 --- /dev/null +++ b/httpclient5/src/examples/org/apache/hc/client5/http/examples/AsyncClientHttp2FullDuplexExchange.java @@ -0,0 +1,147 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.hc.client5.http.examples; + +import java.io.IOException; +import java.net.URI; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.hc.client5.http.impl.async.HttpAsyncClients; +import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.EntityDetails; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler; +import org.apache.hc.core5.http.nio.BasicRequestProducer; +import org.apache.hc.core5.http.nio.BasicResponseConsumer; +import org.apache.hc.core5.http.nio.CapacityChannel; +import org.apache.hc.core5.http.nio.DataStreamChannel; +import org.apache.hc.core5.http.nio.RequestChannel; +import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer; +import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer; +import org.apache.hc.core5.http2.HttpVersionPolicy; +import org.apache.hc.core5.http2.config.H2Config; +import org.apache.hc.core5.io.ShutdownType; +import org.apache.hc.core5.reactor.IOReactorConfig; +import org.apache.hc.core5.util.Timeout; + +/** + * This example demonstrates a full-duplex, streaming HTTP/2 message exchange. + */ +public class AsyncClientHttp2FullDuplexExchange { + + public static void main(final String[] args) throws Exception { + + final IOReactorConfig ioReactorConfig = IOReactorConfig.custom() + .setSoTimeout(Timeout.ofSeconds(5)) + .build(); + + final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal( + HttpVersionPolicy.FORCE_HTTP_2, H2Config.DEFAULT, null, ioReactorConfig); + + client.start(); + + final URI requestUri = new URI("http://http2bin.org/post"); + final BasicRequestProducer requestProducer = new BasicRequestProducer( + "POST", requestUri, new BasicAsyncEntityProducer("stuff", ContentType.TEXT_PLAIN)); + final BasicResponseConsumer responseConsumer = new BasicResponseConsumer<>( + new StringAsyncEntityConsumer()); + + final CountDownLatch latch = new CountDownLatch(1); + client.execute(new AsyncClientExchangeHandler() { + + @Override + public void releaseResources() { + requestProducer.releaseResources(); + responseConsumer.releaseResources(); + latch.countDown(); + } + + @Override + public void cancel() { + System.out.println(requestUri + " cancelled"); + } + + @Override + public void failed(final Exception cause) { + System.out.println(requestUri + "->" + cause); + } + + @Override + public void produceRequest(final RequestChannel channel) throws HttpException, IOException { + requestProducer.sendRequest(channel); + } + + @Override + public int available() { + return requestProducer.available(); + } + + @Override + public void produce(final DataStreamChannel channel) throws IOException { + requestProducer.produce(channel); + } + + @Override + public void consumeInformation(final HttpResponse response) throws HttpException, IOException { + System.out.println(requestUri + "->" + response.getCode()); + } + + @Override + public void consumeResponse(final HttpResponse response, final EntityDetails entityDetails) throws HttpException, IOException { + System.out.println(requestUri + "->" + response.getCode()); + responseConsumer.consumeResponse(response, entityDetails, null); + } + + @Override + public void updateCapacity(final CapacityChannel capacityChannel) throws IOException { + responseConsumer.updateCapacity(capacityChannel); + } + + @Override + public int consume(final ByteBuffer src) throws IOException { + return responseConsumer.consume(src); + } + + @Override + public void streamEnd(final List trailers) throws HttpException, IOException { + responseConsumer.streamEnd(trailers); + } + + }); + latch.await(1, TimeUnit.MINUTES); + + System.out.println("Shutting down"); + client.shutdown(ShutdownType.GRACEFUL); + } + +}