View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.client.util;
20  
21  import java.util.concurrent.CancellationException;
22  import java.util.concurrent.CountDownLatch;
23  import java.util.concurrent.ExecutionException;
24  import java.util.concurrent.Future;
25  import java.util.concurrent.TimeUnit;
26  import java.util.concurrent.TimeoutException;
27  
28  import org.eclipse.jetty.client.HttpContentResponse;
29  import org.eclipse.jetty.client.api.ContentResponse;
30  import org.eclipse.jetty.client.api.Request;
31  import org.eclipse.jetty.client.api.Result;
32  
33  /**
34   * A {@link BufferingResponseListener} that is also a {@link Future}, to allow applications
35   * to block (indefinitely or for a timeout) until {@link #onComplete(Result)} is called,
36   * or to {@link #cancel(boolean) abort} the request/response conversation.
37   * <p>
38   * Typical usage is:
39   * <pre>
40   * Request request = httpClient.newRequest(...)...;
41   * FutureResponseListener listener = new FutureResponseListener(request);
42   * request.send(listener); // Asynchronous send
43   * ContentResponse response = listener.get(5, TimeUnit.SECONDS); // Timed block
44   * </pre>
45   */
46  public class FutureResponseListener extends BufferingResponseListener implements Future<ContentResponse>
47  {
48      private final CountDownLatch latch = new CountDownLatch(1);
49      private final Request request;
50      private ContentResponse response;
51      private Throwable failure;
52      private volatile boolean cancelled;
53  
54      public FutureResponseListener(Request request)
55      {
56          this(request, 2 * 1024 * 1024);
57      }
58  
59      public FutureResponseListener(Request request, int maxLength)
60      {
61          super(maxLength);
62          this.request = request;
63      }
64  
65      public Request getRequest()
66      {
67          return request;
68      }
69  
70      @Override
71      public void onComplete(Result result)
72      {
73          response = new HttpContentResponse(result.getResponse(), getContent(), getMediaType(), getEncoding());
74          failure = result.getFailure();
75          latch.countDown();
76      }
77  
78      @Override
79      public boolean cancel(boolean mayInterruptIfRunning)
80      {
81          cancelled = true;
82          return request.abort(new CancellationException());
83      }
84  
85      @Override
86      public boolean isCancelled()
87      {
88          return cancelled;
89      }
90  
91      @Override
92      public boolean isDone()
93      {
94          return latch.getCount() == 0 || isCancelled();
95      }
96  
97      @Override
98      public ContentResponse get() throws InterruptedException, ExecutionException
99      {
100         latch.await();
101         return getResult();
102     }
103 
104     @Override
105     public ContentResponse get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
106     {
107         boolean expired = !latch.await(timeout, unit);
108         if (expired)
109             throw new TimeoutException();
110         return getResult();
111     }
112 
113     private ContentResponse getResult() throws ExecutionException
114     {
115         if (isCancelled())
116             throw (CancellationException)new CancellationException().initCause(failure);
117         if (failure != null)
118             throw new ExecutionException(failure);
119         return response;
120     }
121 }