View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.hc.core5.http.nio.support;
28  
29  import java.io.IOException;
30  import java.nio.ByteBuffer;
31  import java.util.List;
32  import java.util.concurrent.atomic.AtomicBoolean;
33  
34  import org.apache.hc.core5.concurrent.FutureCallback;
35  import org.apache.hc.core5.http.EntityDetails;
36  import org.apache.hc.core5.http.Header;
37  import org.apache.hc.core5.http.HttpException;
38  import org.apache.hc.core5.http.HttpResponse;
39  import org.apache.hc.core5.http.HttpStatus;
40  import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler;
41  import org.apache.hc.core5.http.nio.AsyncRequestProducer;
42  import org.apache.hc.core5.http.nio.AsyncResponseConsumer;
43  import org.apache.hc.core5.http.nio.CapacityChannel;
44  import org.apache.hc.core5.http.nio.DataStreamChannel;
45  import org.apache.hc.core5.http.nio.RequestChannel;
46  import org.apache.hc.core5.util.Args;
47  
48  /**
49   * @since 5.0
50   */
51  public class BasicClientExchangeHandler<T> implements AsyncClientExchangeHandler {
52  
53      private final AsyncRequestProducer requestProducer;
54      private final AsyncResponseConsumer<T> responseConsumer;
55      private final FutureCallback<T> resultCallback;
56      private final AtomicBoolean outputTerminated;
57  
58      public BasicClientExchangeHandler(
59              final AsyncRequestProducer requestProducer,
60              final AsyncResponseConsumer<T> responseConsumer,
61              final FutureCallback<T> resultCallback) {
62          this.requestProducer = Args.notNull(requestProducer, "Request producer");
63          this.responseConsumer = Args.notNull(responseConsumer, "Response consumer");
64          this.resultCallback = resultCallback;
65          this.outputTerminated = new AtomicBoolean(false);
66      }
67  
68      @Override
69      public void produceRequest(final RequestChannel requestChannel) throws HttpException, IOException {
70          requestProducer.sendRequest(requestChannel);
71      }
72  
73      @Override
74      public int available() {
75          return requestProducer.available();
76      }
77  
78      @Override
79      public void produce(final DataStreamChannel channel) throws IOException {
80          if (outputTerminated.get()) {
81              channel.endStream();
82              return;
83          }
84          requestProducer.produce(channel);
85      }
86  
87      @Override
88      public void consumeInformation(final HttpResponse response) throws HttpException, IOException {
89      }
90  
91      @Override
92      public void consumeResponse(final HttpResponse response, final EntityDetails entityDetails) throws HttpException, IOException {
93          if (response.getCode() >= HttpStatus.SC_CLIENT_ERROR) {
94              outputTerminated.set(true);
95              requestProducer.releaseResources();
96          }
97          responseConsumer.consumeResponse(response, entityDetails, new FutureCallback<T>() {
98  
99              @Override
100             public void completed(final T result) {
101                 releaseResources();
102                 if (resultCallback != null) {
103                     resultCallback.completed(result);
104                 }
105             }
106 
107             @Override
108             public void failed(final Exception ex) {
109                 releaseResources();
110                 if (resultCallback != null) {
111                     resultCallback.failed(ex);
112                 }
113             }
114 
115             @Override
116             public void cancelled() {
117                 releaseResources();
118                 if (resultCallback != null) {
119                     resultCallback.cancelled();
120                 }
121             }
122 
123         });
124     }
125 
126     @Override
127     public void cancel() {
128         releaseResources();
129         if (resultCallback != null) {
130             resultCallback.cancelled();
131         }
132     }
133 
134     @Override
135     public void updateCapacity(final CapacityChannel capacityChannel) throws IOException {
136         responseConsumer.updateCapacity(capacityChannel);
137     }
138 
139     @Override
140     public int consume(final ByteBuffer src) throws IOException {
141         return responseConsumer.consume(src);
142     }
143 
144     @Override
145     public void streamEnd(final List<? extends Header> trailers) throws HttpException, IOException {
146         responseConsumer.streamEnd(trailers);
147     }
148 
149     @Override
150     public final void failed(final Exception cause) {
151         try {
152             requestProducer.failed(cause);
153             responseConsumer.failed(cause);
154         } finally {
155             releaseResources();
156             if (resultCallback != null) {
157                 resultCallback.failed(cause);
158             }
159         }
160     }
161 
162     @Override
163     public final void releaseResources() {
164         requestProducer.releaseResources();
165         responseConsumer.releaseResources();
166     }
167 
168 }