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