View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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.io.IOException;
22  import java.io.OutputStream;
23  import java.nio.ByteBuffer;
24  import java.util.Iterator;
25  
26  import org.eclipse.jetty.client.AsyncContentProvider;
27  import org.eclipse.jetty.client.api.ContentProvider;
28  import org.eclipse.jetty.client.api.Request;
29  import org.eclipse.jetty.client.api.Response;
30  
31  /**
32   * A {@link ContentProvider} that provides content asynchronously through an {@link OutputStream}
33   * similar to {@link DeferredContentProvider}.
34   * <p />
35   * {@link OutputStreamContentProvider} can only be used in conjunction with
36   * {@link Request#send(Response.CompleteListener)} (and not with its blocking counterpart {@link Request#send()})
37   * because it provides content asynchronously.
38   * <p />
39   * The deferred content is provided once by writing to the {@link #getOutputStream() output stream}
40   * and then fully consumed.
41   * Invocations to the {@link #iterator()} method after the first will return an "empty" iterator
42   * because the stream has been consumed on the first invocation.
43   * However, it is possible for subclasses to support multiple invocations of {@link #iterator()}
44   * by overriding {@link #write(ByteBuffer)} and {@link #close()}, copying the bytes and making them
45   * available for subsequent invocations.
46   * <p />
47   * Content must be provided by writing to the {@link #getOutputStream() output stream}, that must be
48   * {@link OutputStream#close() closed} when all content has been provided.
49   * <p />
50   * Example usage:
51   * <pre>
52   * HttpClient httpClient = ...;
53   *
54   * // Use try-with-resources to autoclose the output stream
55   * OutputStreamContentProvider content = new OutputStreamContentProvider();
56   * try (OutputStream output = content.getOutputStream())
57   * {
58   *     httpClient.newRequest("localhost", 8080)
59   *             .content(content)
60   *             .send(new Response.CompleteListener()
61   *             {
62   *                 &#64Override
63   *                 public void onComplete(Result result)
64   *                 {
65   *                     // Your logic here
66   *                 }
67   *             });
68   *
69   *     // At a later time...
70   *     output.write("some content".getBytes());
71   * }
72   * </pre>
73   */
74  public class OutputStreamContentProvider implements AsyncContentProvider
75  {
76      private final DeferredContentProvider deferred = new DeferredContentProvider();
77      private final OutputStream output = new DeferredOutputStream();
78  
79      @Override
80      public long getLength()
81      {
82          return deferred.getLength();
83      }
84  
85      @Override
86      public Iterator<ByteBuffer> iterator()
87      {
88          return deferred.iterator();
89      }
90  
91      @Override
92      public void setListener(Listener listener)
93      {
94          deferred.setListener(listener);
95      }
96  
97      public OutputStream getOutputStream()
98      {
99          return output;
100     }
101 
102     protected void write(ByteBuffer buffer)
103     {
104         deferred.offer(buffer);
105     }
106 
107     protected void close()
108     {
109         deferred.close();
110     }
111 
112     private class DeferredOutputStream extends OutputStream
113     {
114         @Override
115         public void write(int b) throws IOException
116         {
117             write(new byte[]{(byte)b}, 0, 1);
118         }
119 
120         @Override
121         public void write(byte[] b, int off, int len) throws IOException
122         {
123             OutputStreamContentProvider.this.write(ByteBuffer.wrap(b, off, len));
124         }
125 
126         @Override
127         public void close() throws IOException
128         {
129             OutputStreamContentProvider.this.close();
130         }
131     }
132 }