Javadocs.

This commit is contained in:
Simone Bordet 2012-02-22 23:47:45 +01:00
parent 111ae7fa1a
commit 726fda5593
37 changed files with 520 additions and 86 deletions

View File

@ -34,7 +34,14 @@ public class Promise<T> implements Handler<T>, Future<T>
@Override
public void completed(T result)
{
fulfilled(result);
this.promise = result;
latch.countDown();
}
public void failed(Throwable x, T context)
{
this.failure = x;
latch.countDown();
}
@Override
@ -78,16 +85,4 @@ public class Promise<T> implements Handler<T>, Future<T>
throw new ExecutionException(failure);
return promise;
}
public void failed(Throwable x)
{
this.failure = x;
latch.countDown();
}
public void fulfilled(T promise)
{
this.promise = promise;
latch.countDown();
}
}

View File

@ -140,7 +140,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
catch (StreamException x)
{
removeStream(stream);
handler.failed(x);
handler.failed(x, stream);
}
}
}
@ -174,7 +174,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
catch (StreamException x)
{
logger.info("Could not send reset on stream " + rstInfo.getStreamId(), x);
handler.failed(x);
handler.failed(x, null);
}
}
@ -197,7 +197,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
}
catch (StreamException x)
{
handler.failed(x);
handler.failed(x, null);
}
}
@ -212,17 +212,17 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
@Override
public void ping(final Handler<PingInfo> handler)
{
int pingId = pingIds.getAndAdd(2);
PingInfo pingInfo = new PingInfo(pingId);
try
{
int pingId = pingIds.getAndAdd(2);
final PingInfo pingInfo = new PingInfo(pingId);
PingFrame frame = new PingFrame(version, pingId);
control(null, frame, handler, pingInfo);
flush();
}
catch (StreamException x)
{
handler.failed(x);
handler.failed(x, pingInfo);
}
}
@ -250,7 +250,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
}
catch (StreamException x)
{
handler.failed(x);
handler.failed(x, null);
}
}
}
@ -730,7 +730,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
}
@Override
public void failed(Throwable x)
public void failed(Throwable x, FrameBytes frameBytes)
{
throw new SPDYException(x);
}

View File

@ -286,7 +286,7 @@ public class StandardStream implements IStream
catch (StreamException x)
{
logger.debug("Could not send reply on stream " + this, x);
handler.failed(x);
handler.failed(x, null);
session.rst(new RstInfo(getId(), x.getStreamStatus()));
}
}
@ -327,7 +327,7 @@ public class StandardStream implements IStream
catch (StreamException x)
{
logger.debug("Could not send headers on stream " + this, x);
handler.failed(x);
handler.failed(x, null);
session.rst(new RstInfo(getId(), x.getStreamStatus()));
}
}

View File

@ -18,6 +18,9 @@ package org.eclipse.jetty.spdy.api;
import java.nio.ByteBuffer;
/**
* <p>Specialized {@link DataInfo} for {@link ByteBuffer} content.</p>
*/
public class ByteBufferDataInfo extends DataInfo
{
private ByteBuffer buffer;
@ -34,13 +37,13 @@ public class ByteBufferDataInfo extends DataInfo
}
@Override
public int getBytesCount()
public int getContentLength()
{
return buffer.remaining();
}
@Override
public int getBytes(ByteBuffer output)
public int getContent(ByteBuffer output)
{
int length = output.remaining();
if (buffer.remaining() > length)

View File

@ -18,6 +18,9 @@ package org.eclipse.jetty.spdy.api;
import java.nio.ByteBuffer;
/**
* <p>Specialized {@link DataInfo} for byte array content.</p>
*/
public class BytesDataInfo extends DataInfo
{
private byte[] bytes;
@ -35,13 +38,13 @@ public class BytesDataInfo extends DataInfo
}
@Override
public int getBytesCount()
public int getContentLength()
{
return bytes.length - offset;
}
@Override
public int getBytes(ByteBuffer output)
public int getContent(ByteBuffer output)
{
int remaining = output.remaining();
int length = Math.min(bytes.length - offset, remaining);

View File

@ -19,88 +19,171 @@ package org.eclipse.jetty.spdy.api;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
/**
* <p>A container for DATA frames metadata and content bytes.</p>
* <p>Specialized subclasses (like {@link StringDataInfo}) may be used by applications
* to send specific types of content.</p>
* <p>Applications may send multiple instances of {@link DataInfo}, usually of the same
* type, via {@link Stream#data(DataInfo)}. The last instance must have the
* {@link #isClose() close flag} set, so that the client knows that no more content is
* expected.</p>
*/
public abstract class DataInfo
{
public final static byte FLAG_FIN = 1;
/**
* <p>Flag that indicates that this {@link DataInfo} is the last frame in the stream.</p>
*
* @see #isClose()
* @see #getFlags()
*/
public final static byte FLAG_CLOSE = 1;
/**
* <p>Flag that indicates that this {@link DataInfo}'s data is compressed.</p>
*
* @see #isCompress()
* @see #getFlags()
*/
public final static byte FLAG_COMPRESS = 2;
private boolean close;
private boolean compress;
private boolean consumed;
/**
* <p>Creates a new {@link DataInfo} with the given close flag and no compression flag.</p>
*
* @param close the value of the close flag
*/
public DataInfo(boolean close)
{
setClose(close);
}
/**
* <p>Creates a new {@link DataInfo} with the given close flag and given compression flag.</p>
*
* @param close the close flag
* @param compress the compress flag
*/
public DataInfo(boolean close, boolean compress)
{
setClose(close);
setCompress(compress);
}
/**
* @return the value of the compress flag
* @see #setCompress(boolean)
*/
public boolean isCompress()
{
return compress;
}
/**
* @param compress the value of the compress flag
* @see #isCompress()
*/
public void setCompress(boolean compress)
{
this.compress = compress;
}
/**
* @return the value of the close flag
* @see #setClose(boolean)
*/
public boolean isClose()
{
return close;
}
/**
* @param close the value of the close flag
* @see #isClose()
*/
public void setClose(boolean close)
{
this.close = close;
}
/**
* @return the close and compress flags as integer
* @see #FLAG_CLOSE
* @see #FLAG_COMPRESS
*/
public byte getFlags()
{
byte flags = isClose() ? FLAG_FIN : 0;
byte flags = isClose() ? FLAG_CLOSE : 0;
flags |= isCompress() ? FLAG_COMPRESS : 0;
return flags;
}
public abstract int getBytesCount();
/**
* @return the length of the content bytes
* @see #getContent(ByteBuffer)
*/
public abstract int getContentLength();
public abstract int getBytes(ByteBuffer output);
/**
* <p>Copies the content bytes of this {@link DataInfo} into the given {@link ByteBuffer}.</p>
* <p>If the given {@link ByteBuffer} cannot contain the whole content of this {@link DataInfo}
* then this {@link DataInfo} will not be {@link #isConsumed() consumed}, and further content
* may be retrieved by invoking again this method.</p>
*
* @param output the {@link ByteBuffer} to copy to bytes into
* @return the number of bytes copied
* @see #getContentLength()
*/
public abstract int getContent(ByteBuffer output);
/**
* @param charset the charset used to convert the bytes
* @return a String with the content of this {@link DataInfo}
*/
public String asString(String charset)
{
ByteBuffer buffer = ByteBuffer.allocate(getBytesCount());
getBytes(buffer);
ByteBuffer buffer = ByteBuffer.allocate(getContentLength());
getContent(buffer);
buffer.flip();
return Charset.forName(charset).decode(buffer).toString();
}
/**
* @return a byte array with the content of this {@link DataInfo}
*/
public byte[] asBytes()
{
ByteBuffer buffer = ByteBuffer.allocate(getBytesCount());
getBytes(buffer);
ByteBuffer buffer = ByteBuffer.allocate(getContentLength());
getContent(buffer);
buffer.flip();
byte[] result = new byte[buffer.remaining()];
buffer.get(result);
return result;
}
/**
* @return a {@link ByteBuffer} with the content of this {@link DataInfo}
*/
public ByteBuffer asByteBuffer()
{
ByteBuffer buffer = ByteBuffer.allocate(getBytesCount());
getBytes(buffer);
ByteBuffer buffer = ByteBuffer.allocate(getContentLength());
getContent(buffer);
buffer.flip();
return buffer;
}
/**
* @return whether this {@link DataInfo}'s content has been consumed
*/
public boolean isConsumed()
{
return consumed;
}
/**
* @param consumed whether this {@link DataInfo}'s content has been consumed
*/
protected void setConsumed(boolean consumed)
{
this.consumed = consumed;
@ -109,6 +192,6 @@ public abstract class DataInfo
@Override
public String toString()
{
return String.format("DATA @%x length=%d close=%b compress=%b", hashCode(), getBytesCount(), isClose(), isCompress());
return String.format("DATA @%x length=%d close=%b compress=%b", hashCode(), getContentLength(), isClose(), isCompress());
}
}

View File

@ -16,22 +16,38 @@
package org.eclipse.jetty.spdy.api;
/**
* <p>A container for GOAWAY frames metadata: the last good stream id and
* the session status.</p>
*/
public class GoAwayInfo
{
private final int lastStreamId;
private final SessionStatus sessionStatus;
/**
* <p>Creates a new {@link GoAwayInfo} with the given last good stream id and session status</p>
*
* @param lastStreamId the last good stream id
* @param sessionStatus the session status
*/
public GoAwayInfo(int lastStreamId, SessionStatus sessionStatus)
{
this.lastStreamId = lastStreamId;
this.sessionStatus = sessionStatus;
}
/**
* @return the last good stream id
*/
public int getLastStreamId()
{
return lastStreamId;
}
/**
* @return the session status
*/
public SessionStatus getSessionStatus()
{
return sessionStatus;

View File

@ -16,12 +16,36 @@
package org.eclipse.jetty.spdy.api;
/**
* <p>A callback abstraction that handles completed/failed events of asynchronous operations.</p>
* <p>Instances of this class capture a context that is made available on completion
* and failure callbacks.</p>
*
* @param <C> the type of the context object
*/
public interface Handler<C>
{
/**
* <p>Callback invoked when the operation completes.</p>
*
* @param context the context
* @see #failed(Throwable, Object)
*/
public abstract void completed(C context);
public void failed(Throwable x);
/**
* <p>Callback invoked when the operation fails.</p>
*
* @param x the reason for the operation failure
* @param context the context
*/
public void failed(Throwable x, C context);
/**
* <p>Empty implementation of {@link Handler}</p>
*
* @param <C> the type of the context object
*/
public static class Adapter<C> implements Handler<C>
{
@Override
@ -30,7 +54,7 @@ public interface Handler<C>
}
@Override
public void failed(Throwable x)
public void failed(Throwable x, C context)
{
throw new SPDYException(x);
}

View File

@ -24,15 +24,32 @@ import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
/**
* <p>A container for name/value pairs, known as headers.</p>
* <p>A {@link Header} is composed of a case-insensitive name string and
* of a case-sensitive set of value strings.</p>
* <p>The implementation of this class is not thread safe.</p>
*/
public class Headers implements Iterable<Headers.Header>
{
private final Map<String, Header> headers;
/**
* <p>Creates an empty modifiable {@link Headers} instance.</p>
* @see #Headers(Headers, boolean)
*/
public Headers()
{
headers = new LinkedHashMap<>();
}
/**
* <p>Creates a {@link Headers} instance by copying the headers from the given
* {@link Headers} and making it (im)mutable depending on the given {@code immutable} parameter</p>
*
* @param original the {@link Headers} to copy headers from
* @param immutable whether this instance is immutable
*/
public Headers(Headers original, boolean immutable)
{
Map<String, Header> copy = new LinkedHashMap<>();
@ -57,19 +74,32 @@ public class Headers implements Iterable<Headers.Header>
return headers.hashCode();
}
/**
* @return a set of header names
*/
public Set<String> names()
{
Set<String> result = new LinkedHashSet<String>();
Set<String> result = new LinkedHashSet<>();
for (Header header : headers.values())
result.add(header.name);
return result;
}
/**
* @param name the header name
* @return the {@link Header} with the given name, or null if no such header exists
*/
public Header get(String name)
{
return headers.get(name.trim().toLowerCase());
}
/**
* <p>Inserts or replaces the given name/value pair as a single-valued {@link Header}.</p>
*
* @param name the header name
* @param value the header value
*/
public void put(String name, String value)
{
name = name.trim();
@ -77,12 +107,23 @@ public class Headers implements Iterable<Headers.Header>
headers.put(name.toLowerCase(), header);
}
public void put(String name, Header header)
/**
* <p>Inserts or replaces the given {@link Header}, mapped to the {@link Header#name() header's name}</p>
*
* @param header the header to add
*/
public void put(Header header)
{
name = name.trim();
headers.put(name.toLowerCase(), header);
headers.put(header.name().toLowerCase(), header);
}
/**
* <p>Adds the given value to a header with the given name, creating a {@link Header} is none exists
* for the given name.</p>
*
* @param name the header name
* @param value the header value to add
*/
public void add(String name, String value)
{
name = name.trim();
@ -99,27 +140,46 @@ public class Headers implements Iterable<Headers.Header>
}
}
/**
* <p>Removes the {@link Header} with the given name</p>
*
* @param name the name of the header to remove
* @return the removed header, or null if no such header existed
*/
public Header remove(String name)
{
name = name.trim();
return headers.remove(name.toLowerCase());
}
/**
* <p>Empties this {@link Headers} instance from all headers</p>
* @see #isEmpty()
*/
public void clear()
{
headers.clear();
}
/**
* @return whether this {@link Headers} instance is empty
*/
public boolean isEmpty()
{
return headers.isEmpty();
}
public int getSize()
/**
* @return the number of headers
*/
public int size()
{
return headers.size();
}
/**
* @return an iterator over the {@link Header} present in this instance
*/
@Override
public Iterator<Header> iterator()
{
@ -132,6 +192,10 @@ public class Headers implements Iterable<Headers.Header>
return headers.toString();
}
/**
* <p>A named list of string values.</p>
* <p>The name is case-sensitive and there must be at least one value.</p>
*/
public static class Header
{
private final String name;
@ -165,11 +229,17 @@ public class Headers implements Iterable<Headers.Header>
return result;
}
/**
* @return the header's name
*/
public String name()
{
return name;
}
/**
* @return the first header's value
*/
public String value()
{
return values[0];
@ -189,11 +259,17 @@ public class Headers implements Iterable<Headers.Header>
return value == null ? null : Integer.valueOf(value);
}
/**
* @return the header's values
*/
public String[] values()
{
return values;
}
/**
* @return whether the header has multiple values
*/
public boolean hasMultipleValues()
{
return values.length > 1;

View File

@ -16,20 +16,50 @@
package org.eclipse.jetty.spdy.api;
/**
* <p>A container for HEADERS frame metadata and headers.</p>
*/
public class HeadersInfo
{
public static final byte FLAG_FIN = 1;
/**
* <p>Flag that indicates that this {@link HeadersInfo} is the last frame in the stream.</p>
*
* @see #isClose()
* @see #getFlags()
*/
public static final byte FLAG_CLOSE = 1;
/**
* <p>Flag that indicates that the compression of the stream must be reset.</p>
*
* @see #isResetCompression()
* @see #getFlags()
*/
public static final byte FLAG_RESET_COMPRESSION = 2;
private final boolean close;
private final boolean resetCompression;
private final Headers headers;
/**
* <p>Creates a new {@link HeadersInfo} instance with the given headers,
* the given close flag and no reset compression flag</p>
*
* @param headers the {@link Headers}
* @param close the value of the close flag
*/
public HeadersInfo(Headers headers, boolean close)
{
this(headers, close, false);
}
/**
* <p>Creates a new {@link HeadersInfo} instance with the given headers,
* the given close flag and the given reset compression flag</p>
*
* @param headers the {@link Headers}
* @param close the value of the close flag
* @param resetCompression the value of the reset compression flag
*/
public HeadersInfo(Headers headers, boolean close, boolean resetCompression)
{
this.headers = headers;
@ -37,24 +67,38 @@ public class HeadersInfo
this.resetCompression = resetCompression;
}
/**
* @return the value of the close flag
*/
public boolean isClose()
{
return close;
}
/**
* @return the value of the reset compression flag
*/
public boolean isResetCompression()
{
return resetCompression;
}
/**
* @return the {@link Headers}
*/
public Headers getHeaders()
{
return headers;
}
/**
* @return the close and reset compression flags as integer
* @see #FLAG_CLOSE
* @see #FLAG_RESET_COMPRESSION
*/
public byte getFlags()
{
byte flags = isClose() ? FLAG_FIN : 0;
byte flags = isClose() ? FLAG_CLOSE : 0;
flags += isResetCompression() ? FLAG_RESET_COMPRESSION : 0;
return flags;
}

View File

@ -16,15 +16,25 @@
package org.eclipse.jetty.spdy.api;
/**
* <p>A container for PING frames data.</p>
*/
public class PingInfo
{
private final int pingId;
/**
* <p>Creates a {@link PingInfo} with the given ping id</p>
* @param pingId the ping id
*/
public PingInfo(int pingId)
{
this.pingId = pingId;
}
/**
* @return the ping id
*/
public int getPingId()
{
return pingId;

View File

@ -16,37 +16,67 @@
package org.eclipse.jetty.spdy.api;
/**
* <p>A container for SYN_REPLY frames metadata and headers.</p>
*/
public class ReplyInfo
{
public static final byte FLAG_FIN = 1;
/**
* <p>Flag that indicates that this {@link ReplyInfo} is the last frame in the stream.</p>
*
* @see #isClose()
* @see #getFlags()
*/
public static final byte FLAG_CLOSE = 1;
private final Headers headers;
private final boolean close;
/**
* <p>Creates a new {@link ReplyInfo} instance with empty headers and the given close flag.</p>
*
* @param close the value of the close flag
*/
public ReplyInfo(boolean close)
{
this(new Headers(), close);
}
/**
* <p>Creates a {@link ReplyInfo} instance with the given headers and the given close flag.</p>
*
* @param headers the {@link Headers}
* @param close the value of the close flag
*/
public ReplyInfo(Headers headers, boolean close)
{
this.headers = headers;
this.close = close;
}
/**
* @return the {@link Headers}
*/
public Headers getHeaders()
{
return headers;
}
/**
* @return the value of the close flag
*/
public boolean isClose()
{
return close;
}
/**
* @return the close and reset compression flags as integer
* @see #FLAG_CLOSE
*/
public byte getFlags()
{
return isClose() ? FLAG_FIN : 0;
return isClose() ? FLAG_CLOSE : 0;
}
@Override

View File

@ -16,22 +16,37 @@
package org.eclipse.jetty.spdy.api;
/**
* <p>A container for RST_STREAM frames data: the stream id and the stream status.</p>
*/
public class RstInfo
{
private final int streamId;
private final StreamStatus streamStatus;
/**
* <p>Creates a new {@link RstInfo} with the given stream id and stream status</p>
*
* @param streamId the stream id
* @param streamStatus the stream status
*/
public RstInfo(int streamId, StreamStatus streamStatus)
{
this.streamId = streamId;
this.streamStatus = streamStatus;
}
/**
* @return the stream id
*/
public int getStreamId()
{
return streamId;
}
/**
* @return the stream status
*/
public StreamStatus getStreamStatus()
{
return streamStatus;

View File

@ -18,7 +18,7 @@ package org.eclipse.jetty.spdy.api;
/**
* <p>An unrecoverable exception that signals to the application that
* something wrong happened</p>
* something wrong happened.</p>
*/
public class SPDYException extends RuntimeException
{

View File

@ -19,11 +19,25 @@ package org.eclipse.jetty.spdy.api;
import java.util.HashMap;
import java.util.Map;
/**
* <p>An enumeration of session statuses.</p>
*/
public enum SessionStatus
{
/**
* <p>The session status indicating no errors</p>
*/
OK(0),
/**
* <p>The session status indicating a protocol error</p>
*/
PROTOCOL_ERROR(1);
/**
* @param code the session status code
* @return a {@link SessionStatus} from the given code,
* or null if no status exists
*/
public static SessionStatus from(int code)
{
return Mapper.codes.get(code);
@ -37,6 +51,9 @@ public enum SessionStatus
Mapper.codes.put(code, this);
}
/**
* @return the code of this {@link SessionStatus}
*/
public int getCode()
{
return code;

View File

@ -19,18 +19,62 @@ package org.eclipse.jetty.spdy.api;
import java.util.HashMap;
import java.util.Map;
/**
* <p>An enumeration of stream statuses.</p>
*/
public enum StreamStatus
{
/**
* <p>The stream status indicating a protocol error</p>
*/
PROTOCOL_ERROR(1, 1),
/**
* <p>The stream status indicating that the stream is not valid</p>
*/
INVALID_STREAM(2, 2),
/**
* <p>The stream status indicating that the stream has been refused</p>
*/
REFUSED_STREAM(3, 3),
/**
* <p>The stream status indicating that the implementation does not support the SPDY version of the stream</p>
*/
UNSUPPORTED_VERSION(4, 4),
/**
* <p>The stream status indicating that the stream is no longer needed</p>
*/
CANCEL_STREAM(5, 5),
INTERNAL_ERROR(6, -1),
/**
* <p>The stream status indicating an implementation error</p>
*/
INTERNAL_ERROR(6, 11),
/**
* <p>The stream status indicating a flow control error</p>
*/
FLOW_CONTROL_ERROR(7, 6),
/**
* <p>The stream status indicating a stream opened more than once</p>
*/
STREAM_IN_USE(-1, 7),
STREAM_ALREADY_CLOSED(-1, 8);
/**
* <p>The stream status indicating data on a stream already closed</p>
*/
STREAM_ALREADY_CLOSED(-1, 8),
/**
* <p>The stream status indicating credentials not valid</p>
*/
INVALID_CREDENTIALS(-1, 9),
/**
* <p>The stream status indicating that the implementation could not support a frame too large</p>
*/
FRAME_TOO_LARGE(-1, 10);
/**
* @param version the SPDY protocol version
* @param code the stream status code
* @return a {@link StreamStatus} from the given version and code,
* or null if no such status exists
*/
public static StreamStatus from(short version, int code)
{
switch (version)
@ -57,6 +101,10 @@ public enum StreamStatus
Mapper.v3Codes.put(v3Code, this);
}
/**
* @param version the SPDY protocol version
* @return the stream status code
*/
public int getCode(short version)
{
switch (version)

View File

@ -19,6 +19,9 @@ package org.eclipse.jetty.spdy.api;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
/**
* <p>Specialized {@link DataInfo} for {@link String} content.</p>
*/
public class StringDataInfo extends DataInfo
{
private byte[] bytes;
@ -36,13 +39,13 @@ public class StringDataInfo extends DataInfo
}
@Override
public int getBytesCount()
public int getContentLength()
{
return bytes.length - offset;
}
@Override
public int getBytes(ByteBuffer output)
public int getContent(ByteBuffer output)
{
int remaining = output.remaining();
int length = Math.min(bytes.length - offset, remaining);

View File

@ -16,9 +16,18 @@
package org.eclipse.jetty.spdy.api;
/**
* <p>A container for SYN_STREAM frames metadata and data.</p>
*/
public class SynInfo
{
public static final byte FLAG_FIN = 1;
/**
* <p>Flag that indicates that this {@link DataInfo} is the last frame in the stream.</p>
*
* @see #isClose()
* @see #getFlags()
*/
public static final byte FLAG_CLOSE = 1;
public static final byte FLAG_UNIDIRECTIONAL = 2;
private final boolean close;
@ -27,16 +36,39 @@ public class SynInfo
private final byte priority;
private final Headers headers;
/**
* <p>Creates a new {@link SynInfo} instance with empty headers and the given close flag,
* not unidirectional, without associated stream, and with default priority.</p>
*
* @param close the value of the close flag
*/
public SynInfo(boolean close)
{
this(new Headers(), close);
}
/**
* <p>Creates a {@link ReplyInfo} instance with the given headers and the given close flag,
* not unidirectional, without associated stream, and with default priority.</p>
*
* @param headers the {@link Headers}
* @param close the value of the close flag
*/
public SynInfo(Headers headers, boolean close)
{
this(headers, close, false, 0, (byte)0);
}
/**
* <p>Creates a {@link ReplyInfo} instance with the given headers and the given close flag,
* the given unidirectional flag, the given associated stream, and with the given priority.</p>
*
* @param headers the {@link Headers}
* @param close the value of the close flag
* @param unidirectional the value of the unidirectional flag
* @param associatedStreamId the associated stream id
* @param priority the priority
*/
public SynInfo(Headers headers, boolean close, boolean unidirectional, int associatedStreamId, byte priority)
{
this.close = close;
@ -46,34 +78,54 @@ public class SynInfo
this.headers = headers;
}
/**
* @return the value of the close flag
*/
public boolean isClose()
{
return close;
}
/**
* @return the value of the unidirectional flag
*/
public boolean isUnidirectional()
{
return unidirectional;
}
/**
* @return the associated stream id
*/
public int getAssociatedStreamId()
{
return associatedStreamId;
}
/**
* @return the priority
*/
public byte getPriority()
{
return priority;
}
/**
* @return the {@link Headers}
*/
public Headers getHeaders()
{
return headers;
}
/**
* @return the close and unidirectional flags as integer
* @see #FLAG_CLOSE
* @see #FLAG_UNIDIRECTIONAL
*/
public byte getFlags()
{
byte flags = isClose() ? FLAG_FIN : 0;
byte flags = isClose() ? FLAG_CLOSE : 0;
flags += isUnidirectional() ? FLAG_UNIDIRECTIONAL : 0;
return flags;
}

View File

@ -19,10 +19,25 @@ package org.eclipse.jetty.spdy.api.server;
import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.SessionFrameListener;
/**
* <p>Specific, server-side, {@link SessionFrameListener}.</p>
* <p>In addition to {@link SessionFrameListener}, this listener adds method
* {@link #onConnect(Session)} that is called when a client first connects to the
* server and may be used by a server-side application to send a SETTINGS frame
* to configure the connection before the client can open any stream.</p>
*/
public interface ServerSessionFrameListener extends SessionFrameListener
{
/**
* <p>Callback invoked when a client opens a connection.</p>
*
* @param session the session
*/
public void onConnect(Session session);
/**
* <p>Empty implementation of {@link ServerSessionFrameListener}</p>
*/
public static class Adapter extends SessionFrameListener.Adapter implements ServerSessionFrameListener
{
@Override

View File

@ -50,7 +50,7 @@ public class DataFrame
public boolean isClose()
{
return (flags & DataInfo.FLAG_FIN) == DataInfo.FLAG_FIN;
return (flags & DataInfo.FLAG_CLOSE) == DataInfo.FLAG_CLOSE;
}
public boolean isCompress()

View File

@ -60,7 +60,7 @@ public class HeadersFrame extends ControlFrame
public boolean isClose()
{
return (getFlags() & HeadersInfo.FLAG_FIN) == HeadersInfo.FLAG_FIN;
return (getFlags() & HeadersInfo.FLAG_CLOSE) == HeadersInfo.FLAG_CLOSE;
}
public boolean isResetCompression()

View File

@ -43,7 +43,7 @@ public class SynReplyFrame extends ControlFrame
public boolean isClose()
{
return (getFlags() & ReplyInfo.FLAG_FIN) == ReplyInfo.FLAG_FIN;
return (getFlags() & ReplyInfo.FLAG_CLOSE) == ReplyInfo.FLAG_CLOSE;
}
@Override

View File

@ -57,7 +57,7 @@ public class SynStreamFrame extends ControlFrame
public boolean isClose()
{
return (getFlags() & SynInfo.FLAG_FIN) == SynInfo.FLAG_FIN;
return (getFlags() & SynInfo.FLAG_CLOSE) == SynInfo.FLAG_CLOSE;
}
public boolean isUnidirectional()

View File

@ -28,14 +28,14 @@ public class DataFrameGenerator
ByteBuffer buffer = ByteBuffer.allocateDirect(DataFrame.HEADER_LENGTH + windowSize);
buffer.position(DataFrame.HEADER_LENGTH);
// Guaranteed to always be >= 0
int read = dataInfo.getBytes(buffer);
int read = dataInfo.getContent(buffer);
buffer.putInt(0, streamId & 0x7F_FF_FF_FF);
buffer.putInt(4, read & 0x00_FF_FF_FF);
// TODO: compression can be done here, as long as we have one DataFrameGenerator per stream
// since the compression context for data is per-stream, without dictionary
byte flags = dataInfo.isConsumed() && dataInfo.isClose() ? DataInfo.FLAG_FIN : 0;
byte flags = dataInfo.isConsumed() && dataInfo.isClose() ? DataInfo.FLAG_CLOSE : 0;
buffer.put(4, flags);
buffer.flip();

View File

@ -40,8 +40,8 @@ public class HeadersBlockGenerator
{
// TODO: ByteArrayOutputStream is quite inefficient, but grows on demand; optimize using ByteBuffer ?
Charset iso1 = Charset.forName("ISO-8859-1");
ByteArrayOutputStream buffer = new ByteArrayOutputStream(headers.getSize() * 64);
writeCount(version, buffer, headers.getSize());
ByteArrayOutputStream buffer = new ByteArrayOutputStream(headers.size() * 64);
writeCount(version, buffer, headers.size());
for (Headers.Header header : headers)
{
String name = header.name();

View File

@ -80,7 +80,7 @@ public class HeadersBodyParser extends ControlFrameBodyParser
if (headersBlockParser.parse(version, length, buffer))
{
byte flags = controlFrameParser.getFlags();
if (flags != 0 && flags != HeadersInfo.FLAG_FIN && flags != HeadersInfo.FLAG_RESET_COMPRESSION)
if (flags != 0 && flags != HeadersInfo.FLAG_CLOSE && flags != HeadersInfo.FLAG_RESET_COMPRESSION)
throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.HEADERS);
HeadersFrame frame = new HeadersFrame(version, flags, streamId, new Headers(headers, true));

View File

@ -120,7 +120,7 @@ public class SynReplyBodyParser extends ControlFrameBodyParser
if (headersBlockParser.parse(version, length, buffer))
{
byte flags = controlFrameParser.getFlags();
if (flags != 0 && flags != ReplyInfo.FLAG_FIN)
if (flags != 0 && flags != ReplyInfo.FLAG_CLOSE)
throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.SYN_REPLY);
SynReplyFrame frame = new SynReplyFrame(version, flags, streamId, new Headers(headers, true));

View File

@ -126,7 +126,7 @@ public class SynStreamBodyParser extends ControlFrameBodyParser
{
byte flags = controlFrameParser.getFlags();
// TODO: can it be both FIN and UNIDIRECTIONAL ?
if (flags != 0 && flags != SynInfo.FLAG_FIN && flags != SynInfo.FLAG_UNIDIRECTIONAL)
if (flags != 0 && flags != SynInfo.FLAG_CLOSE && flags != SynInfo.FLAG_UNIDIRECTIONAL)
throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.SYN_STREAM);
SynStreamFrame frame = new SynStreamFrame(version, flags, streamId, associatedStreamId, priority, new Headers(headers, true));

View File

@ -37,7 +37,7 @@ public class ServerUsageTest
// Get the http response, fill headers and data
Headers replyHeaders = new Headers();
replyHeaders.put("host", synHeaders.get("host"));
replyHeaders.put(synHeaders.get("host"));
// Sends a reply
stream.reply(new ReplyInfo(replyHeaders, false));

View File

@ -58,7 +58,7 @@ public class DataGenerateParseTest
Assert.assertNotNull(frame2);
Assert.assertEquals(streamId, frame2.getStreamId());
Assert.assertEquals(DataInfo.FLAG_FIN, frame2.getFlags());
Assert.assertEquals(DataInfo.FLAG_CLOSE, frame2.getFlags());
Assert.assertEquals(length, frame2.getLength());
Assert.assertEquals(length, listener.getData().remaining());
}
@ -84,7 +84,7 @@ public class DataGenerateParseTest
Assert.assertNotNull(frame2);
Assert.assertEquals(streamId, frame2.getStreamId());
Assert.assertEquals(DataInfo.FLAG_FIN, frame2.getFlags());
Assert.assertEquals(DataInfo.FLAG_CLOSE, frame2.getFlags());
Assert.assertEquals(length, frame2.getLength());
Assert.assertEquals(length, listener.getData().remaining());
}

View File

@ -32,7 +32,7 @@ public class SynReplyGenerateParseTest
@Test
public void testGenerateParse() throws Exception
{
byte flags = ReplyInfo.FLAG_FIN;
byte flags = ReplyInfo.FLAG_CLOSE;
int streamId = 13;
Headers headers = new Headers();
headers.put("a", "b");
@ -60,7 +60,7 @@ public class SynReplyGenerateParseTest
@Test
public void testGenerateParseOneByteAtATime() throws Exception
{
byte flags = ReplyInfo.FLAG_FIN;
byte flags = ReplyInfo.FLAG_CLOSE;
int streamId = 13;
Headers headers = new Headers();
headers.put("a", "b");

View File

@ -32,7 +32,7 @@ public class SynStreamGenerateParseTest
@Test
public void testGenerateParse() throws Exception
{
byte flags = SynInfo.FLAG_FIN;
byte flags = SynInfo.FLAG_CLOSE;
int streamId = 13;
int associatedStreamId = 11;
byte priority = 3;
@ -65,7 +65,7 @@ public class SynStreamGenerateParseTest
@Test
public void testGenerateParseOneByteAtATime() throws Exception
{
byte flags = SynInfo.FLAG_FIN;
byte flags = SynInfo.FLAG_CLOSE;
int streamId = 13;
int associatedStreamId = 11;
byte priority = 3;

View File

@ -592,7 +592,7 @@ public class ServerHTTPSPDYTest
@Override
public void onData(Stream stream, DataInfo dataInfo)
{
contentBytes.addAndGet(dataInfo.getBytesCount());
contentBytes.addAndGet(dataInfo.getContentLength());
if (dataInfo.isClose())
{
Assert.assertEquals(data.length, contentBytes.get());
@ -649,7 +649,7 @@ public class ServerHTTPSPDYTest
@Override
public void onData(Stream stream, DataInfo dataInfo)
{
contentBytes.addAndGet(dataInfo.getBytesCount());
contentBytes.addAndGet(dataInfo.getContentLength());
if (dataInfo.isClose())
{
Assert.assertEquals(2 * data.length, contentBytes.get());

View File

@ -134,7 +134,7 @@ public class SPDYAsyncConnection extends AbstractConnection implements AsyncConn
catch (Exception x)
{
close(false);
handler.failed(x);
handler.failed(x, context);
}
finally
{

View File

@ -123,8 +123,8 @@ public class ConcurrentSynDataReplyDataTest extends AbstractTest
public void onData(Stream stream, DataInfo dataInfo)
{
Assert.assertEquals(1, latch.getCount());
ByteBuffer buffer = ByteBuffer.allocate(dataInfo.getBytesCount());
dataInfo.getBytes(buffer);
ByteBuffer buffer = ByteBuffer.allocate(dataInfo.getContentLength());
dataInfo.getContent(buffer);
Assert.assertTrue(dataInfo.isConsumed());
latch.countDown();
}

View File

@ -55,7 +55,7 @@ public class FlowControlTest extends AbstractTest
@Override
public void onData(Stream stream, DataInfo dataInfo)
{
bytes.addAndGet(dataInfo.getBytesCount());
bytes.addAndGet(dataInfo.getContentLength());
if (dataInfo.isClose())
dataLatch.countDown();
}
@ -88,7 +88,7 @@ public class FlowControlTest extends AbstractTest
@Override
public void onData(Stream stream, DataInfo dataInfo)
{
bytes.addAndGet(dataInfo.getBytesCount());
bytes.addAndGet(dataInfo.getContentLength());
if (dataInfo.isClose())
dataLatch.countDown();
}
@ -114,7 +114,7 @@ public class FlowControlTest extends AbstractTest
@Override
public void onData(Stream stream, DataInfo dataInfo)
{
bytes.addAndGet(dataInfo.getBytesCount());
bytes.addAndGet(dataInfo.getContentLength());
if (dataInfo.isClose())
dataLatch.countDown();
}
@ -146,7 +146,7 @@ public class FlowControlTest extends AbstractTest
@Override
public void onData(Stream stream, DataInfo dataInfo)
{
bytes.addAndGet(dataInfo.getBytesCount());
bytes.addAndGet(dataInfo.getContentLength());
if (dataInfo.isClose())
dataLatch.countDown();
}

View File

@ -139,7 +139,7 @@ public class SynReplyTest extends AbstractTest
ByteBuffer buffer = ByteBuffer.allocate(2);
while (!dataInfo.isConsumed())
{
dataInfo.getBytes(buffer);
dataInfo.getContent(buffer);
buffer.flip();
bytes.write(buffer.array(), buffer.arrayOffset(), buffer.remaining());
buffer.clear();
@ -309,8 +309,8 @@ public class SynReplyTest extends AbstractTest
@Override
public void onData(Stream stream, DataInfo dataInfo)
{
ByteBuffer buffer = ByteBuffer.allocate(dataInfo.getBytesCount());
dataInfo.getBytes(buffer);
ByteBuffer buffer = ByteBuffer.allocate(dataInfo.getContentLength());
dataInfo.getContent(buffer);
buffer.flip();
String data = Charset.forName("UTF-8").decode(buffer).toString();
Assert.assertEquals(serverData, data);