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.spdy.api; 20 21 import java.nio.channels.WritePendingException; 22 import java.util.Set; 23 import java.util.concurrent.ExecutionException; 24 import java.util.concurrent.TimeoutException; 25 26 import org.eclipse.jetty.util.Callback; 27 import org.eclipse.jetty.util.Promise; 28 29 /** 30 * <p>A {@link Stream} represents a bidirectional exchange of data on top of a {@link Session}.</p> <p>Differently from 31 * socket streams, where the input and output streams are permanently associated with the socket (and hence with the 32 * connection that the socket represents), there can be multiple SPDY streams for a SPDY session.</p> <p>SPDY streams 33 * may terminate without this implying that the SPDY session is terminated.</p> <p>If SPDY is used to transport the HTTP 34 * protocol, then a SPDY stream maps to a HTTP request/response cycle, and after the request/response cycle is 35 * completed, the stream is closed, and other streams may be opened. Differently from HTTP, though, multiple SPDY 36 * streams may be opened concurrently on the same SPDY session.</p> <p>Like {@link Session}, {@link Stream} is the 37 * active part and by calling its API applications can generate events on the stream; conversely, {@link 38 * StreamFrameListener} is the passive part, and its callbacks are invoked when events happen on the stream.</p> <p>A 39 * {@link Stream} can send multiple data frames one after the other but implementations use a flow control mechanism 40 * that only sends the data frames if the other end has signalled that it can accept the frame.</p> <p>Data frames 41 * should be sent sequentially only when the previous frame has been completely sent. The reason for this requirement is 42 * to avoid potentially confusing code such as:</p> 43 * <pre> 44 * // WRONG CODE, DO NOT USE IT 45 * final Stream stream = ...; 46 * stream.data(StringDataInfo("chunk1", false), 5, TimeUnit.SECONDS, new Handler<Void>() { ... }); 47 * stream.data(StringDataInfo("chunk2", true), 1, TimeUnit.SECONDS, new Handler<Void>() { ... }); 48 * </pre> 49 * <p>where the second call to {@link #data(DataInfo, Callback)} has a timeout smaller than the previous call.</p> 50 * <p>The behavior of such style of invocations is unspecified (it may even throw an exception - similar to {@link 51 * WritePendingException}).</p> <p>The correct sending of data frames is the following:</p> 52 * <pre> 53 * final Stream stream = ...; 54 * ... 55 * // Blocking version 56 * stream.data(new StringDataInfo("chunk1", false)).get(1, TimeUnit.SECONDS); 57 * stream.data(new StringDataInfo("chunk2", true)).get(1, TimeUnit.SECONDS); 58 * 59 * // Asynchronous version 60 * stream.data(new StringDataInfo("chunk1", false), 1, TimeUnit.SECONDS, new Handler.Adapter<Void>() 61 * { 62 * public void completed(Void context) 63 * { 64 * stream.data(new StringDataInfo("chunk2", true)); 65 * } 66 * }); 67 * </pre> 68 * 69 * @see StreamFrameListener 70 */ 71 public interface Stream 72 { 73 /** 74 * @return the id of this stream 75 */ 76 public int getId(); 77 78 /** 79 * @return the priority of this stream 80 */ 81 public byte getPriority(); 82 83 /** 84 * @return the session this stream is associated to 85 */ 86 public Session getSession(); 87 88 /** 89 * <p>Initiate a unidirectional spdy pushstream associated to this stream asynchronously<p> <p>Callers may use the 90 * returned future to get the pushstream once it got created</p> 91 * 92 * @param pushInfo the metadata to send on stream creation 93 * @return a future containing the stream once it got established 94 * @see #push(PushInfo, Promise) 95 */ 96 public Stream push(PushInfo pushInfo) throws InterruptedException, ExecutionException, TimeoutException; 97 98 /** 99 * <p>Initiate a unidirectional spdy pushstream associated to this stream asynchronously<p> <p>Callers may pass a 100 * non-null completion promise to be notified of when the pushstream has been established.</p> 101 * 102 * @param pushInfo the metadata to send on stream creation 103 * @param promise the completion promise that gets notified once the pushstream is established 104 * @see #push(PushInfo) 105 */ 106 public void push(PushInfo pushInfo, Promise<Stream> promise); 107 108 /** 109 * <p>Sends asynchronously a SYN_REPLY frame in response to a SYN_STREAM frame.</p> <p>Callers may use the returned 110 * future to wait for the reply to be actually sent.</p> 111 * 112 * @param replyInfo the metadata to send 113 * @see #reply(ReplyInfo, Callback) 114 * @see SessionFrameListener#onSyn(Stream, SynInfo) 115 */ 116 public void reply(ReplyInfo replyInfo) throws InterruptedException, ExecutionException, TimeoutException; 117 118 /** 119 * <p>Sends asynchronously a SYN_REPLY frame in response to a SYN_STREAM frame.</p> <p>Callers may pass a non-null 120 * completion callback to be notified of when the reply has been actually sent.</p> 121 * 122 * @param replyInfo the metadata to send 123 * @param callback the completion callback that gets notified of reply sent 124 * @see #reply(ReplyInfo) 125 */ 126 public void reply(ReplyInfo replyInfo, Callback callback); 127 128 /** 129 * <p>Sends asynchronously a DATA frame on this stream.</p> <p>DATA frames should always be sent after a SYN_REPLY 130 * frame.</p> <p>Callers may use the returned future to wait for the data to be actually sent.</p> 131 * 132 * @param dataInfo the metadata to send 133 * @see #data(DataInfo, Callback) 134 * @see #reply(ReplyInfo) 135 */ 136 public void data(DataInfo dataInfo) throws InterruptedException, ExecutionException, TimeoutException; 137 138 /** 139 * <p>Sends asynchronously a DATA frame on this stream.</p> <p>DATA frames should always be sent after a SYN_REPLY 140 * frame.</p> <p>Callers may pass a non-null completion callback to be notified of when the data has been actually 141 * sent.</p> 142 * 143 * @param dataInfo the metadata to send 144 * @param callback the completion callback that gets notified of data sent 145 * @see #data(DataInfo) 146 */ 147 public void data(DataInfo dataInfo, Callback callback); 148 149 /** 150 * <p>Sends asynchronously a HEADER frame on this stream.</p> <p>HEADERS frames should always be sent after a 151 * SYN_REPLY frame.</p> <p>Callers may use the returned future to wait for the headers to be actually sent.</p> 152 * 153 * @param headersInfo the metadata to send 154 * @see #headers(HeadersInfo, Callback) 155 * @see #reply(ReplyInfo) 156 */ 157 public void headers(HeadersInfo headersInfo) throws InterruptedException, ExecutionException, TimeoutException; 158 159 /** 160 * <p>Sends asynchronously a HEADER frame on this stream.</p> <p>HEADERS frames should always be sent after a 161 * SYN_REPLY frame.</p> <p>Callers may pass a non-null completion callback to be notified of when the headers have 162 * been actually sent.</p> 163 * 164 * @param headersInfo the metadata to send 165 * @param callback the completion callback that gets notified of headers sent 166 * @see #headers(HeadersInfo) 167 */ 168 public void headers(HeadersInfo headersInfo, Callback callback); 169 170 /** 171 * @return whether this stream is unidirectional or not 172 */ 173 public boolean isUnidirectional(); 174 175 /** 176 * @return whether this stream has been reset 177 */ 178 public boolean isReset(); 179 180 /** 181 * @return whether this stream has been closed by both parties 182 * @see #isHalfClosed() 183 */ 184 public boolean isClosed(); 185 186 /** 187 * @return whether this stream has been closed by one party only 188 * @see #isClosed() 189 */ 190 public boolean isHalfClosed(); 191 192 /** 193 * @param key the attribute key 194 * @return an arbitrary object associated with the given key to this stream or null if no object can be found for 195 * the given key. 196 * @see #setAttribute(String, Object) 197 */ 198 public Object getAttribute(String key); 199 200 /** 201 * @param key the attribute key 202 * @param value an arbitrary object to associate with the given key to this stream 203 * @see #getAttribute(String) 204 * @see #removeAttribute(String) 205 */ 206 public void setAttribute(String key, Object value); 207 208 /** 209 * @param key the attribute key 210 * @return the arbitrary object associated with the given key to this stream 211 * @see #setAttribute(String, Object) 212 */ 213 public Object removeAttribute(String key); 214 215 /** 216 * @return the associated parent stream or null if this is not an associated stream 217 */ 218 public Stream getAssociatedStream(); 219 220 /** 221 * @return associated child streams or an empty set if no associated streams exist 222 */ 223 public Set<Stream> getPushedStreams(); 224 225 /** 226 * Get the idle timeout set for this particular stream 227 * @return the idle timeout 228 */ 229 public long getIdleTimeout(); 230 231 /** 232 * Set an idle timeout for this stream 233 * @param timeout 234 */ 235 public void setIdleTimeout(long timeout); 236 237 }