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.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 }