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 * @return a future to wait for the reply to be sent
114 * @see #reply(ReplyInfo, Callback)
115 * @see SessionFrameListener#onSyn(Stream, SynInfo)
116 */
117 public void reply(ReplyInfo replyInfo) throws InterruptedException, ExecutionException, TimeoutException;
118
119 /**
120 * <p>Sends asynchronously a SYN_REPLY frame in response to a SYN_STREAM frame.</p> <p>Callers may pass a non-null
121 * completion callback to be notified of when the reply has been actually sent.</p>
122 *
123 * @param replyInfo the metadata to send
124 * @param callback the completion callback that gets notified of reply sent
125 * @see #reply(ReplyInfo)
126 */
127 public void reply(ReplyInfo replyInfo, Callback callback);
128
129 /**
130 * <p>Sends asynchronously a DATA frame on this stream.</p> <p>DATA frames should always be sent after a SYN_REPLY
131 * frame.</p> <p>Callers may use the returned future to wait for the data to be actually sent.</p>
132 *
133 * @param dataInfo the metadata to send
134 * @return a future to wait for the data to be sent
135 * @see #data(DataInfo, Callback)
136 * @see #reply(ReplyInfo)
137 */
138 public void data(DataInfo dataInfo) throws InterruptedException, ExecutionException, TimeoutException;
139
140 /**
141 * <p>Sends asynchronously a DATA frame on this stream.</p> <p>DATA frames should always be sent after a SYN_REPLY
142 * frame.</p> <p>Callers may pass a non-null completion callback to be notified of when the data has been actually
143 * sent.</p>
144 *
145 * @param dataInfo the metadata to send
146 * @param callback the completion callback that gets notified of data sent
147 * @see #data(DataInfo)
148 */
149 public void data(DataInfo dataInfo, Callback callback);
150
151 /**
152 * <p>Sends asynchronously a HEADER frame on this stream.</p> <p>HEADERS frames should always be sent after a
153 * SYN_REPLY frame.</p> <p>Callers may use the returned future to wait for the headers to be actually sent.</p>
154 *
155 * @param headersInfo the metadata to send
156 * @return a future to wait for the headers to be sent
157 * @see #headers(HeadersInfo, Callback
158 * @see #reply(ReplyInfo)
159 */
160 public void headers(HeadersInfo headersInfo) throws InterruptedException, ExecutionException, TimeoutException;
161
162 /**
163 * <p>Sends asynchronously a HEADER frame on this stream.</p> <p>HEADERS frames should always be sent after a
164 * SYN_REPLY frame.</p> <p>Callers may pass a non-null completion callback to be notified of when the headers have
165 * been actually sent.</p>
166 *
167 * @param headersInfo the metadata to send
168 * @param callback the completion callback that gets notified of headers sent
169 * @see #headers(HeadersInfo)
170 */
171 public void headers(HeadersInfo headersInfo, Callback callback);
172
173 /**
174 * @return whether this stream is unidirectional or not
175 */
176 public boolean isUnidirectional();
177
178 /**
179 * @return whether this stream has been reset
180 */
181 public boolean isReset();
182
183 /**
184 * @return whether this stream has been closed by both parties
185 * @see #isHalfClosed()
186 */
187 public boolean isClosed();
188
189 /**
190 * @return whether this stream has been closed by one party only
191 * @see #isClosed()
192 */
193 public boolean isHalfClosed();
194
195 /**
196 * @param key the attribute key
197 * @return an arbitrary object associated with the given key to this stream or null if no object can be found for
198 * the given key.
199 * @see #setAttribute(String, Object)
200 */
201 public Object getAttribute(String key);
202
203 /**
204 * @param key the attribute key
205 * @param value an arbitrary object to associate with the given key to this stream
206 * @see #getAttribute(String)
207 * @see #removeAttribute(String)
208 */
209 public void setAttribute(String key, Object value);
210
211 /**
212 * @param key the attribute key
213 * @return the arbitrary object associated with the given key to this stream
214 * @see #setAttribute(String, Object)
215 */
216 public Object removeAttribute(String key);
217
218 /**
219 * @return the associated parent stream or null if this is not an associated stream
220 */
221 public Stream getAssociatedStream();
222
223 /**
224 * @return associated child streams or an empty set if no associated streams exist
225 */
226 public Set<Stream> getPushedStreams();
227
228 }