Let the plugin determine whether to flush the output stream after each

packet.
This commit is contained in:
akwizgran
2011-12-08 22:13:35 +00:00
parent 844ae8f0a7
commit 2494ff1a1e
28 changed files with 223 additions and 159 deletions

View File

@@ -28,9 +28,8 @@ public interface Plugin {
long getPollingInterval(); long getPollingInterval();
/** /**
* Attempts to establish connections using the current transport and * Attempts to establish connections to all contacts, passing any created
* configuration properties, and passes any created connections to the * connections to the callback.
* callback.
*/ */
void poll(); void poll();

View File

@@ -4,6 +4,8 @@ import java.io.IOException;
public interface ProtocolWriter { public interface ProtocolWriter {
void flush() throws IOException;
int getMaxBatchesForAck(long capacity); int getMaxBatchesForAck(long capacity);
int getMaxMessagesForOffer(long capacity); int getMaxMessagesForOffer(long capacity);

View File

@@ -4,5 +4,5 @@ import java.io.OutputStream;
public interface ProtocolWriterFactory { public interface ProtocolWriterFactory {
ProtocolWriter createProtocolWriter(OutputStream out); ProtocolWriter createProtocolWriter(OutputStream out, boolean flush);
} }

View File

@@ -14,6 +14,11 @@ public interface BatchTransportWriter {
/** Returns an output stream for writing to the transport. */ /** Returns an output stream for writing to the transport. */
OutputStream getOutputStream(); OutputStream getOutputStream();
/**
* Returns true if the output stream should be flushed after each packet.
*/
boolean shouldFlush();
/** /**
* Closes the writer and disposes of any associated resources. The * Closes the writer and disposes of any associated resources. The
* argument indicates whether the writer is being closed because of an * argument indicates whether the writer is being closed because of an

View File

@@ -17,6 +17,11 @@ public interface StreamTransportConnection {
/** Returns an output stream for writing to the connection. */ /** Returns an output stream for writing to the connection. */
OutputStream getOutputStream() throws IOException; OutputStream getOutputStream() throws IOException;
/**
* Returns true if the output stream should be flushed after each packet.
*/
boolean shouldFlush();
/** /**
* Closes the connection and disposes of any associated resources. The * Closes the connection and disposes of any associated resources. The
* first argument indicates whether the connection is being closed because * first argument indicates whether the connection is being closed because

View File

@@ -10,19 +10,19 @@ public abstract class AbstractPlugin implements Plugin {
protected final Executor pluginExecutor; protected final Executor pluginExecutor;
protected boolean started = false; // Locking: this protected boolean running = false; // Locking: this
protected AbstractPlugin(@PluginExecutor Executor pluginExecutor) { protected AbstractPlugin(@PluginExecutor Executor pluginExecutor) {
this.pluginExecutor = pluginExecutor; this.pluginExecutor = pluginExecutor;
} }
public synchronized void start() throws IOException { public synchronized void start() throws IOException {
if(started) throw new IllegalStateException(); if(running) throw new IllegalStateException();
started = true; running = true;
} }
public synchronized void stop() throws IOException { public synchronized void stop() throws IOException {
if(!started) throw new IllegalStateException(); if(!running) throw new IllegalStateException();
started = false; running = false;
} }
} }

View File

@@ -78,30 +78,17 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
} }
throw new IOException(e.toString()); throw new IOException(e.toString());
} }
pluginExecutor.execute(createContactSocketBinder()); pluginExecutor.execute(new Runnable() {
}
@Override
public synchronized void stop() throws IOException {
super.stop();
if(socket != null) {
socket.close();
socket = null;
}
}
private Runnable createContactSocketBinder() {
return new Runnable() {
public void run() { public void run() {
bindContactSocket(); bindContactSocket();
} }
}; });
} }
private void bindContactSocket() { private void bindContactSocket() {
String uuid; String uuid;
synchronized(this) { synchronized(this) {
if(!started) return; if(!running) return;
uuid = getUuid(); uuid = getUuid();
makeDeviceDiscoverable(); makeDeviceDiscoverable();
} }
@@ -115,7 +102,7 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
return; return;
} }
synchronized(this) { synchronized(this) {
if(!started) { if(!running) {
try { try {
scn.close(); scn.close();
} catch(IOException e) { } catch(IOException e) {
@@ -134,7 +121,7 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
} }
private synchronized String getUuid() { private synchronized String getUuid() {
assert started; assert running;
TransportProperties p = callback.getLocalProperties(); TransportProperties p = callback.getLocalProperties();
String uuid = p.get("uuid"); String uuid = p.get("uuid");
if(uuid == null) { if(uuid == null) {
@@ -149,7 +136,7 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
} }
private synchronized void makeDeviceDiscoverable() { private synchronized void makeDeviceDiscoverable() {
assert started; assert running;
// Try to make the device discoverable (requires root on Linux) // Try to make the device discoverable (requires root on Linux)
try { try {
localDevice.setDiscoverable(DiscoveryAgent.GIAC); localDevice.setDiscoverable(DiscoveryAgent.GIAC);
@@ -169,7 +156,7 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
StreamConnectionNotifier scn; StreamConnectionNotifier scn;
StreamConnection s; StreamConnection s;
synchronized(this) { synchronized(this) {
if(!started) return; if(!running) return;
scn = socket; scn = socket;
} }
try { try {
@@ -185,6 +172,15 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
} }
} }
@Override
public synchronized void stop() throws IOException {
super.stop();
if(socket != null) {
socket.close();
socket = null;
}
}
public boolean shouldPoll() { public boolean shouldPoll() {
return true; return true;
} }
@@ -193,21 +189,24 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
return pollingInterval; return pollingInterval;
} }
public synchronized void poll() { public void poll() {
if(!started) return; synchronized(this) {
pluginExecutor.execute(createConnectors()); if(!running) return;
} }
pluginExecutor.execute(new Runnable() {
private Runnable createConnectors() {
return new Runnable() {
public void run() { public void run() {
connectAndCallBack(); connectAndCallBack();
} }
}; });
} }
private void connectAndCallBack() { private void connectAndCallBack() {
Map<ContactId, String> discovered = discoverContactUrls(); Map<ContactId, TransportProperties> remote;
synchronized(this) {
if(!running) return;
remote = callback.getRemoteProperties();
}
Map<ContactId, String> discovered = discoverContactUrls(remote);
for(Entry<ContactId, String> e : discovered.entrySet()) { for(Entry<ContactId, String> e : discovered.entrySet()) {
ContactId c = e.getKey(); ContactId c = e.getKey();
String url = e.getValue(); String url = e.getValue();
@@ -216,13 +215,12 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
} }
} }
private Map<ContactId, String> discoverContactUrls() { private Map<ContactId, String> discoverContactUrls(
Map<ContactId, TransportProperties> remote) {
DiscoveryAgent discoveryAgent; DiscoveryAgent discoveryAgent;
Map<ContactId, TransportProperties> remote;
synchronized(this) { synchronized(this) {
if(!started) return Collections.emptyMap(); if(!running) return Collections.emptyMap();
discoveryAgent = localDevice.getDiscoveryAgent(); discoveryAgent = localDevice.getDiscoveryAgent();
remote = callback.getRemoteProperties();
} }
Map<String, ContactId> addresses = new HashMap<String, ContactId>(); Map<String, ContactId> addresses = new HashMap<String, ContactId>();
Map<ContactId, String> uuids = new HashMap<ContactId, String>(); Map<ContactId, String> uuids = new HashMap<ContactId, String>();
@@ -236,18 +234,17 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
uuids.put(c, uuid); uuids.put(c, uuid);
} }
} }
if(addresses.isEmpty()) return Collections.emptyMap();
ContactListener listener = new ContactListener(discoveryAgent, ContactListener listener = new ContactListener(discoveryAgent,
Collections.unmodifiableMap(addresses), Collections.unmodifiableMap(addresses),
Collections.unmodifiableMap(uuids)); Collections.unmodifiableMap(uuids));
synchronized(discoveryLock) { synchronized(discoveryLock) {
try { try {
discoveryAgent.startInquiry(DiscoveryAgent.GIAC, listener); discoveryAgent.startInquiry(DiscoveryAgent.GIAC, listener);
return listener.waitForUrls();
} catch(BluetoothStateException e) { } catch(BluetoothStateException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
return Collections.emptyMap(); return Collections.emptyMap();
}
try {
return listener.waitForUrls();
} catch(InterruptedException e) { } catch(InterruptedException e) {
if(LOG.isLoggable(Level.INFO)) if(LOG.isLoggable(Level.INFO))
LOG.info("Interrupted while waiting for URLs"); LOG.info("Interrupted while waiting for URLs");
@@ -259,12 +256,10 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
private StreamTransportConnection connect(ContactId c, String url) { private StreamTransportConnection connect(ContactId c, String url) {
synchronized(this) { synchronized(this) {
if(!started) return null; if(!running) return null;
} }
try { try {
if(LOG.isLoggable(Level.INFO)) LOG.info("Connecting to " + url);
StreamConnection s = (StreamConnection) Connector.open(url); StreamConnection s = (StreamConnection) Connector.open(url);
if(LOG.isLoggable(Level.INFO)) LOG.info("Connected");
return new BluetoothTransportConnection(s); return new BluetoothTransportConnection(s);
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
@@ -273,7 +268,14 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
} }
public StreamTransportConnection createConnection(ContactId c) { public StreamTransportConnection createConnection(ContactId c) {
String url = discoverContactUrls().get(c); Map<ContactId, TransportProperties> remote;
synchronized(this) {
if(!running) return null;
remote = callback.getRemoteProperties();
}
if(!remote.containsKey(c)) return null;
remote = Collections.singletonMap(c, remote.get(c));
String url = discoverContactUrls(remote).get(c);
return url == null ? null : connect(c, url); return url == null ? null : connect(c, url);
} }
@@ -325,7 +327,7 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
private void createInvitationConnection(ConnectionCallback c) { private void createInvitationConnection(ConnectionCallback c) {
DiscoveryAgent discoveryAgent; DiscoveryAgent discoveryAgent;
synchronized(this) { synchronized(this) {
if(!started) return; if(!running) return;
discoveryAgent = localDevice.getDiscoveryAgent(); discoveryAgent = localDevice.getDiscoveryAgent();
} }
// Try to discover the other party until the invitation times out // Try to discover the other party until the invitation times out
@@ -350,7 +352,7 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
} }
} }
synchronized(this) { synchronized(this) {
if(!started) return; if(!running) return;
} }
} }
if(url == null) return; if(url == null) return;
@@ -365,7 +367,7 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
private void bindInvitationSocket(final ConnectionCallback c) { private void bindInvitationSocket(final ConnectionCallback c) {
synchronized(this) { synchronized(this) {
if(!started) return; if(!running) return;
makeDeviceDiscoverable(); makeDeviceDiscoverable();
} }
// Bind the socket // Bind the socket
@@ -400,7 +402,7 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
private void acceptInvitationConnection(ConnectionCallback c, private void acceptInvitationConnection(ConnectionCallback c,
StreamConnectionNotifier scn) { StreamConnectionNotifier scn) {
synchronized(this) { synchronized(this) {
if(!started) return; if(!running) return;
} }
try { try {
StreamConnection s = scn.acceptAndOpen(); StreamConnection s = scn.acceptAndOpen();

View File

@@ -29,6 +29,10 @@ class BluetoothTransportConnection implements StreamTransportConnection {
return stream.openOutputStream(); return stream.openOutputStream();
} }
public boolean shouldFlush() {
return true;
}
public void dispose(boolean exception, boolean recognised) { public void dispose(boolean exception, boolean recognised) {
try { try {
stream.close(); stream.close();

View File

@@ -64,7 +64,7 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
private BatchTransportWriter createWriter(String filename) { private BatchTransportWriter createWriter(String filename) {
synchronized(this) { synchronized(this) {
if(!started) return null; if(!running) return null;
} }
File dir = chooseOutputDirectory(); File dir = chooseOutputDirectory();
if(dir == null || !dir.exists() || !dir.isDirectory()) return null; if(dir == null || !dir.exists() || !dir.isDirectory()) return null;
@@ -86,7 +86,7 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
} }
protected synchronized void createReaderFromFile(final File f) { protected synchronized void createReaderFromFile(final File f) {
if(!started) return; if(!running) return;
pluginExecutor.execute(new ReaderCreator(f)); pluginExecutor.execute(new ReaderCreator(f));
} }

View File

@@ -34,6 +34,10 @@ class FileTransportWriter implements BatchTransportWriter {
return out; return out;
} }
public boolean shouldFlush() {
return false;
}
public void dispose(boolean exception) { public void dispose(boolean exception) {
try { try {
out.close(); out.close();

View File

@@ -58,7 +58,7 @@ implements RemovableDriveMonitor.Callback {
} }
public long getPollingInterval() { public long getPollingInterval() {
return 0L; throw new UnsupportedOperationException();
} }
public void poll() { public void poll() {

View File

@@ -53,19 +53,20 @@ class SimpleSocketPlugin extends SocketPlugin {
@Override @Override
protected Socket createClientSocket() throws IOException { protected Socket createClientSocket() throws IOException {
assert started; assert running;
return new Socket(); return new Socket();
} }
@Override @Override
protected ServerSocket createServerSocket() throws IOException { protected ServerSocket createServerSocket() throws IOException {
assert started; assert running;
return new ServerSocket(); return new ServerSocket();
} }
// Locking: this
@Override @Override
protected synchronized SocketAddress getLocalSocketAddress() { protected SocketAddress getLocalSocketAddress() {
assert started; assert running;
SocketAddress addr = createSocketAddress(callback.getLocalProperties()); SocketAddress addr = createSocketAddress(callback.getLocalProperties());
if(addr == null) { if(addr == null) {
try { try {
@@ -87,9 +88,10 @@ class SimpleSocketPlugin extends SocketPlugin {
boolean link = addr.isLinkLocalAddress(); boolean link = addr.isLinkLocalAddress();
boolean site = addr.isSiteLocalAddress(); boolean site = addr.isSiteLocalAddress();
if(lan == (link || site)) { if(lan == (link || site)) {
if(LOG.isLoggable(Level.INFO)) if(LOG.isLoggable(Level.INFO)) {
LOG.info("Choosing interface " LOG.info("Choosing interface "
+ addr.getHostAddress()); + addr.getHostAddress());
}
return addr; return addr;
} }
} }
@@ -99,9 +101,10 @@ class SimpleSocketPlugin extends SocketPlugin {
for(NetworkInterface iface : ifaces) { for(NetworkInterface iface : ifaces) {
for(InetAddress addr : Collections.list(iface.getInetAddresses())) { for(InetAddress addr : Collections.list(iface.getInetAddresses())) {
if(!addr.isLoopbackAddress()) { if(!addr.isLoopbackAddress()) {
if(LOG.isLoggable(Level.INFO)) if(LOG.isLoggable(Level.INFO)) {
LOG.info("Accepting interface " LOG.info("Accepting interface "
+ addr.getHostAddress()); + addr.getHostAddress());
}
return addr; return addr;
} }
} }
@@ -109,16 +112,17 @@ class SimpleSocketPlugin extends SocketPlugin {
throw new IOException("No suitable interfaces"); throw new IOException("No suitable interfaces");
} }
// Locking: this
@Override @Override
protected synchronized SocketAddress getRemoteSocketAddress(ContactId c) { protected SocketAddress getRemoteSocketAddress(ContactId c) {
assert started; assert running;
TransportProperties p = callback.getRemoteProperties().get(c); TransportProperties p = callback.getRemoteProperties().get(c);
return p == null ? null : createSocketAddress(p); return p == null ? null : createSocketAddress(p);
} }
private synchronized SocketAddress createSocketAddress( // Locking: this
TransportProperties p) { private SocketAddress createSocketAddress(TransportProperties p) {
assert started; assert running;
assert p != null; assert p != null;
String host = p.get("external"); String host = p.get("external");
if(host == null) host = p.get("internal"); if(host == null) host = p.get("internal");
@@ -133,9 +137,10 @@ class SimpleSocketPlugin extends SocketPlugin {
return new InetSocketAddress(host, port); return new InetSocketAddress(host, port);
} }
// Locking: this
@Override @Override
protected synchronized void setLocalSocketAddress(SocketAddress s) { protected void setLocalSocketAddress(SocketAddress s) {
assert started; assert running;
if(!(s instanceof InetSocketAddress)) if(!(s instanceof InetSocketAddress))
throw new IllegalArgumentException(); throw new IllegalArgumentException();
InetSocketAddress i = (InetSocketAddress) s; InetSocketAddress i = (InetSocketAddress) s;

View File

@@ -4,11 +4,13 @@ import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import net.sf.briar.api.ContactId; import net.sf.briar.api.ContactId;
import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.plugins.PluginExecutor; import net.sf.briar.api.plugins.PluginExecutor;
import net.sf.briar.api.plugins.StreamPlugin; import net.sf.briar.api.plugins.StreamPlugin;
import net.sf.briar.api.plugins.StreamPluginCallback; import net.sf.briar.api.plugins.StreamPluginCallback;
@@ -54,7 +56,7 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
ServerSocket ss = null; ServerSocket ss = null;
try { try {
synchronized(this) { synchronized(this) {
if(!started) return; if(!running) return;
addr = getLocalSocketAddress(); addr = getLocalSocketAddress();
ss = createServerSocket(); ss = createServerSocket();
if(addr == null || ss == null) return; if(addr == null || ss == null) return;
@@ -77,7 +79,7 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
return; return;
} }
synchronized(this) { synchronized(this) {
if(!started) { if(!running) {
try { try {
ss.close(); ss.close();
} catch(IOException e) { } catch(IOException e) {
@@ -93,7 +95,7 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
while(true) { while(true) {
Socket s; Socket s;
synchronized(this) { synchronized(this) {
if(!started) return; if(!running) return;
} }
try { try {
s = ss.accept(); s = ss.accept();
@@ -119,21 +121,19 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
if(socket != null) socket.close(); if(socket != null) socket.close();
} }
public synchronized void poll() { public void poll() {
// Subclasses may not support polling Map<ContactId, TransportProperties> remote;
if(!shouldPoll()) throw new UnsupportedOperationException(); synchronized(this) {
if(!started) return; if(!running) return;
for(ContactId c : callback.getRemoteProperties().keySet()) { remote = callback.getRemoteProperties();
pluginExecutor.execute(createConnector(c)); }
for(final ContactId c : remote.keySet()) {
pluginExecutor.execute(new Runnable() {
public void run() {
connectAndCallBack(c);
}
});
} }
}
private Runnable createConnector(final ContactId c) {
return new Runnable() {
public void run() {
connectAndCallBack(c);
}
};
} }
private void connectAndCallBack(ContactId c) { private void connectAndCallBack(ContactId c) {
@@ -146,7 +146,7 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
Socket s; Socket s;
try { try {
synchronized(this) { synchronized(this) {
if(!started) return null; if(!running) return null;
addr = getRemoteSocketAddress(c); addr = getRemoteSocketAddress(c);
s = createClientSocket(); s = createClientSocket();
if(addr == null || s == null) return null; if(addr == null || s == null) return null;

View File

@@ -28,6 +28,10 @@ class SocketTransportConnection implements StreamTransportConnection {
return socket.getOutputStream(); return socket.getOutputStream();
} }
public boolean shouldFlush() {
return true;
}
public void dispose(boolean exception, boolean recognised) { public void dispose(boolean exception, boolean recognised) {
try { try {
socket.close(); socket.close();

View File

@@ -21,7 +21,8 @@ class ProtocolWriterFactoryImpl implements ProtocolWriterFactory {
this.writerFactory = writerFactory; this.writerFactory = writerFactory;
} }
public ProtocolWriter createProtocolWriter(OutputStream out) { public ProtocolWriter createProtocolWriter(OutputStream out,
return new ProtocolWriterImpl(serial, writerFactory, out); boolean flush) {
return new ProtocolWriterImpl(serial, writerFactory, out, flush);
} }
} }

View File

@@ -27,12 +27,14 @@ class ProtocolWriterImpl implements ProtocolWriter {
private final SerialComponent serial; private final SerialComponent serial;
private final OutputStream out; private final OutputStream out;
private final boolean flush;
private final Writer w; private final Writer w;
ProtocolWriterImpl(SerialComponent serial, WriterFactory writerFactory, ProtocolWriterImpl(SerialComponent serial, WriterFactory writerFactory,
OutputStream out) { OutputStream out, boolean flush) {
this.serial = serial; this.serial = serial;
this.out = out; this.out = out;
this.flush = flush;
w = writerFactory.createWriter(out); w = writerFactory.createWriter(out);
} }
@@ -67,6 +69,7 @@ class ProtocolWriterImpl implements ProtocolWriter {
w.writeListStart(); w.writeListStart();
for(BatchId b : a.getBatchIds()) w.writeBytes(b.getBytes()); for(BatchId b : a.getBatchIds()) w.writeBytes(b.getBytes());
w.writeListEnd(); w.writeListEnd();
if(flush) out.flush();
} }
public void writeBatch(RawBatch b) throws IOException { public void writeBatch(RawBatch b) throws IOException {
@@ -74,6 +77,7 @@ class ProtocolWriterImpl implements ProtocolWriter {
w.writeListStart(); w.writeListStart();
for(byte[] raw : b.getMessages()) out.write(raw); for(byte[] raw : b.getMessages()) out.write(raw);
w.writeListEnd(); w.writeListEnd();
if(flush) out.flush();
} }
public void writeOffer(Offer o) throws IOException { public void writeOffer(Offer o) throws IOException {
@@ -81,6 +85,7 @@ class ProtocolWriterImpl implements ProtocolWriter {
w.writeListStart(); w.writeListStart();
for(MessageId m : o.getMessageIds()) w.writeBytes(m.getBytes()); for(MessageId m : o.getMessageIds()) w.writeBytes(m.getBytes());
w.writeListEnd(); w.writeListEnd();
if(flush) out.flush();
} }
public void writeRequest(Request r) throws IOException { public void writeRequest(Request r) throws IOException {
@@ -100,6 +105,7 @@ class ProtocolWriterImpl implements ProtocolWriter {
w.writeStructId(Types.REQUEST); w.writeStructId(Types.REQUEST);
w.writeUint7((byte) (bytes * 8 - length)); w.writeUint7((byte) (bytes * 8 - length));
w.writeBytes(bitmap); w.writeBytes(bitmap);
if(flush) out.flush();
} }
public void writeSubscriptionUpdate(SubscriptionUpdate s) public void writeSubscriptionUpdate(SubscriptionUpdate s)
@@ -112,6 +118,7 @@ class ProtocolWriterImpl implements ProtocolWriter {
} }
w.writeMapEnd(); w.writeMapEnd();
w.writeInt64(s.getTimestamp()); w.writeInt64(s.getTimestamp());
if(flush) out.flush();
} }
private void writeGroup(Writer w, Group g) throws IOException { private void writeGroup(Writer w, Group g) throws IOException {
@@ -133,5 +140,10 @@ class ProtocolWriterImpl implements ProtocolWriter {
} }
w.writeListEnd(); w.writeListEnd();
w.writeInt64(t.getTimestamp()); w.writeInt64(t.getTimestamp());
if(flush) out.flush();
}
public void flush() throws IOException {
out.flush();
} }
} }

View File

@@ -55,7 +55,8 @@ class OutgoingBatchConnection {
transport.getOutputStream(), transport.getCapacity(), transport.getOutputStream(), transport.getCapacity(),
ctx.getSecret()); ctx.getSecret());
OutputStream out = conn.getOutputStream(); OutputStream out = conn.getOutputStream();
ProtocolWriter writer = protoFactory.createProtocolWriter(out); ProtocolWriter writer = protoFactory.createProtocolWriter(out,
transport.shouldFlush());
// There should be enough space for a packet // There should be enough space for a packet
long capacity = conn.getRemainingCapacity(); long capacity = conn.getRemainingCapacity();
if(capacity < MAX_PACKET_LENGTH) throw new EOFException(); if(capacity < MAX_PACKET_LENGTH) throw new EOFException();
@@ -88,8 +89,7 @@ class OutgoingBatchConnection {
capacity = writer.getMessageCapacityForBatch(capacity); capacity = writer.getMessageCapacityForBatch(capacity);
b = db.generateBatch(contactId, (int) capacity); b = db.generateBatch(contactId, (int) capacity);
} }
// Flush the output stream writer.flush();
out.flush();
transport.dispose(false); transport.dispose(false);
} catch(DbException e) { } catch(DbException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());

View File

@@ -26,11 +26,11 @@ class IncomingStreamConnection extends StreamConnection {
ConnectionWriterFactory connWriterFactory, ConnectionWriterFactory connWriterFactory,
ProtocolReaderFactory protoReaderFactory, ProtocolReaderFactory protoReaderFactory,
ProtocolWriterFactory protoWriterFactory, ProtocolWriterFactory protoWriterFactory,
ConnectionContext ctx, StreamTransportConnection connection, ConnectionContext ctx, StreamTransportConnection transport,
byte[] tag) { byte[] tag) {
super(dbExecutor, verificationExecutor, db, connReaderFactory, super(dbExecutor, verificationExecutor, db, connReaderFactory,
connWriterFactory, protoReaderFactory, protoWriterFactory, connWriterFactory, protoReaderFactory, protoWriterFactory,
ctx.getContactId(), connection); ctx.getContactId(), transport);
this.ctx = ctx; this.ctx = ctx;
this.tag = tag; this.tag = tag;
} }

View File

@@ -31,10 +31,10 @@ class OutgoingStreamConnection extends StreamConnection {
ProtocolReaderFactory protoReaderFactory, ProtocolReaderFactory protoReaderFactory,
ProtocolWriterFactory protoWriterFactory, ContactId contactId, ProtocolWriterFactory protoWriterFactory, ContactId contactId,
TransportIndex transportIndex, TransportIndex transportIndex,
StreamTransportConnection connection) { StreamTransportConnection transport) {
super(dbExecutor, verificationExecutor, db, connReaderFactory, super(dbExecutor, verificationExecutor, db, connReaderFactory,
connWriterFactory, protoReaderFactory, protoWriterFactory, connWriterFactory, protoReaderFactory, protoWriterFactory,
contactId, connection); contactId, transport);
this.transportIndex = transportIndex; this.transportIndex = transportIndex;
} }

View File

@@ -191,7 +191,8 @@ abstract class StreamConnection implements DatabaseListener {
try { try {
db.addListener(this); db.addListener(this);
OutputStream out = createConnectionWriter().getOutputStream(); OutputStream out = createConnectionWriter().getOutputStream();
writer = protoWriterFactory.createProtocolWriter(out); writer = protoWriterFactory.createProtocolWriter(out,
transport.shouldFlush());
// Send the initial packets: transports, subs, acks, offer // Send the initial packets: transports, subs, acks, offer
dbExecutor.execute(new GenerateTransportUpdate()); dbExecutor.execute(new GenerateTransportUpdate());
dbExecutor.execute(new GenerateSubscriptionUpdate()); dbExecutor.execute(new GenerateSubscriptionUpdate());
@@ -203,6 +204,7 @@ abstract class StreamConnection implements DatabaseListener {
if(task == CLOSE) break; if(task == CLOSE) break;
task.run(); task.run();
} }
writer.flush();
if(!disposed.getAndSet(true)) transport.dispose(false, true); if(!disposed.getAndSet(true)) transport.dispose(false, true);
} catch(DbException e) { } catch(DbException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());

View File

@@ -77,53 +77,58 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
private class DispatchBatchConnection implements Runnable { private class DispatchBatchConnection implements Runnable {
private final TransportId t; private final TransportId transportId;
private final BatchTransportReader r; private final BatchTransportReader transport;
private DispatchBatchConnection(TransportId t, BatchTransportReader r) { private DispatchBatchConnection(TransportId transportId,
this.t = t; BatchTransportReader transport) {
this.r = r; this.transportId = transportId;
this.transport = transport;
} }
public void run() { public void run() {
try { try {
byte[] tag = readTag(r.getInputStream()); byte[] tag = readTag(transport.getInputStream());
ConnectionContext ctx = recogniser.acceptConnection(t, tag); ConnectionContext ctx = recogniser.acceptConnection(transportId,
if(ctx == null) r.dispose(false, false); tag);
else batchConnFactory.createIncomingConnection(ctx, r, tag); if(ctx == null) transport.dispose(false, false);
else batchConnFactory.createIncomingConnection(ctx, transport,
tag);
} catch(DbException e) { } catch(DbException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
r.dispose(true, false); transport.dispose(true, false);
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
r.dispose(true, false); transport.dispose(true, false);
} }
} }
} }
private class DispatchStreamConnection implements Runnable { private class DispatchStreamConnection implements Runnable {
private final TransportId t; private final TransportId transportId;
private final StreamTransportConnection s; private final StreamTransportConnection transport;
private DispatchStreamConnection(TransportId t, private DispatchStreamConnection(TransportId transportId,
StreamTransportConnection s) { StreamTransportConnection transport) {
this.t = t; this.transportId = transportId;
this.s = s; this.transport = transport;
} }
public void run() { public void run() {
try { try {
byte[] tag = readTag(s.getInputStream()); byte[] tag = readTag(transport.getInputStream());
ConnectionContext ctx = recogniser.acceptConnection(t, tag); ConnectionContext ctx = recogniser.acceptConnection(transportId,
if(ctx == null) s.dispose(false, false); tag);
else streamConnFactory.createIncomingConnection(ctx, s, tag); if(ctx == null) transport.dispose(false, false);
else streamConnFactory.createIncomingConnection(ctx, transport,
tag);
} catch(DbException e) { } catch(DbException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
s.dispose(true, false); transport.dispose(true, false);
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
s.dispose(true, false); transport.dispose(true, false);
} }
} }
} }

View File

@@ -139,10 +139,11 @@ public class ProtocolIntegrationTest extends TestCase {
ConnectionWriter conn = connectionWriterFactory.createConnectionWriter( ConnectionWriter conn = connectionWriterFactory.createConnectionWriter(
out, Long.MAX_VALUE, secret.clone()); out, Long.MAX_VALUE, secret.clone());
OutputStream out1 = conn.getOutputStream(); OutputStream out1 = conn.getOutputStream();
ProtocolWriter proto = protocolWriterFactory.createProtocolWriter(out1); ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out1,
false);
Ack a = packetFactory.createAck(Collections.singletonList(ack)); Ack a = packetFactory.createAck(Collections.singletonList(ack));
proto.writeAck(a); writer.writeAck(a);
Collection<byte[]> batch = Arrays.asList(new byte[][] { Collection<byte[]> batch = Arrays.asList(new byte[][] {
message.getSerialised(), message.getSerialised(),
@@ -151,7 +152,7 @@ public class ProtocolIntegrationTest extends TestCase {
message3.getSerialised() message3.getSerialised()
}); });
RawBatch b = packetFactory.createBatch(batch); RawBatch b = packetFactory.createBatch(batch);
proto.writeBatch(b); writer.writeBatch(b);
Collection<MessageId> offer = Arrays.asList(new MessageId[] { Collection<MessageId> offer = Arrays.asList(new MessageId[] {
message.getId(), message.getId(),
@@ -160,13 +161,13 @@ public class ProtocolIntegrationTest extends TestCase {
message3.getId() message3.getId()
}); });
Offer o = packetFactory.createOffer(offer); Offer o = packetFactory.createOffer(offer);
proto.writeOffer(o); writer.writeOffer(o);
BitSet requested = new BitSet(4); BitSet requested = new BitSet(4);
requested.set(1); requested.set(1);
requested.set(3); requested.set(3);
Request r = packetFactory.createRequest(requested, 4); Request r = packetFactory.createRequest(requested, 4);
proto.writeRequest(r); writer.writeRequest(r);
// Use a LinkedHashMap for predictable iteration order // Use a LinkedHashMap for predictable iteration order
Map<Group, Long> subs = new LinkedHashMap<Group, Long>(); Map<Group, Long> subs = new LinkedHashMap<Group, Long>();
@@ -174,13 +175,13 @@ public class ProtocolIntegrationTest extends TestCase {
subs.put(group1, 0L); subs.put(group1, 0L);
SubscriptionUpdate s = packetFactory.createSubscriptionUpdate(subs, SubscriptionUpdate s = packetFactory.createSubscriptionUpdate(subs,
timestamp); timestamp);
proto.writeSubscriptionUpdate(s); writer.writeSubscriptionUpdate(s);
TransportUpdate t = packetFactory.createTransportUpdate(transports, TransportUpdate t = packetFactory.createTransportUpdate(transports,
timestamp); timestamp);
proto.writeTransportUpdate(t); writer.writeTransportUpdate(t);
out1.flush(); writer.flush();
return out.toByteArray(); return out.toByteArray();
} }
@@ -188,20 +189,19 @@ public class ProtocolIntegrationTest extends TestCase {
InputStream in = new ByteArrayInputStream(connectionData); InputStream in = new ByteArrayInputStream(connectionData);
byte[] tag = new byte[TAG_LENGTH]; byte[] tag = new byte[TAG_LENGTH];
assertEquals(TAG_LENGTH, in.read(tag, 0, TAG_LENGTH)); assertEquals(TAG_LENGTH, in.read(tag, 0, TAG_LENGTH));
ConnectionReader r = connectionReaderFactory.createConnectionReader(in, ConnectionReader conn = connectionReaderFactory.createConnectionReader(
secret.clone(), tag); in, secret.clone(), tag);
in = r.getInputStream(); InputStream in1 = conn.getInputStream();
ProtocolReader protocolReader = ProtocolReader reader = protocolReaderFactory.createProtocolReader(in1);
protocolReaderFactory.createProtocolReader(in);
// Read the ack // Read the ack
assertTrue(protocolReader.hasAck()); assertTrue(reader.hasAck());
Ack a = protocolReader.readAck(); Ack a = reader.readAck();
assertEquals(Collections.singletonList(ack), a.getBatchIds()); assertEquals(Collections.singletonList(ack), a.getBatchIds());
// Read and verify the batch // Read and verify the batch
assertTrue(protocolReader.hasBatch()); assertTrue(reader.hasBatch());
Batch b = protocolReader.readBatch().verify(); Batch b = reader.readBatch().verify();
Collection<Message> messages = b.getMessages(); Collection<Message> messages = b.getMessages();
assertEquals(4, messages.size()); assertEquals(4, messages.size());
Iterator<Message> it = messages.iterator(); Iterator<Message> it = messages.iterator();
@@ -211,8 +211,8 @@ public class ProtocolIntegrationTest extends TestCase {
checkMessageEquality(message3, it.next()); checkMessageEquality(message3, it.next());
// Read the offer // Read the offer
assertTrue(protocolReader.hasOffer()); assertTrue(reader.hasOffer());
Offer o = protocolReader.readOffer(); Offer o = reader.readOffer();
Collection<MessageId> offered = o.getMessageIds(); Collection<MessageId> offered = o.getMessageIds();
assertEquals(4, offered.size()); assertEquals(4, offered.size());
Iterator<MessageId> it1 = offered.iterator(); Iterator<MessageId> it1 = offered.iterator();
@@ -222,8 +222,8 @@ public class ProtocolIntegrationTest extends TestCase {
assertEquals(message3.getId(), it1.next()); assertEquals(message3.getId(), it1.next());
// Read the request // Read the request
assertTrue(protocolReader.hasRequest()); assertTrue(reader.hasRequest());
Request req = protocolReader.readRequest(); Request req = reader.readRequest();
BitSet requested = req.getBitmap(); BitSet requested = req.getBitmap();
assertFalse(requested.get(0)); assertFalse(requested.get(0));
assertTrue(requested.get(1)); assertTrue(requested.get(1));
@@ -233,8 +233,8 @@ public class ProtocolIntegrationTest extends TestCase {
assertEquals(2, requested.cardinality()); assertEquals(2, requested.cardinality());
// Read the subscription update // Read the subscription update
assertTrue(protocolReader.hasSubscriptionUpdate()); assertTrue(reader.hasSubscriptionUpdate());
SubscriptionUpdate s = protocolReader.readSubscriptionUpdate(); SubscriptionUpdate s = reader.readSubscriptionUpdate();
Map<Group, Long> subs = s.getSubscriptions(); Map<Group, Long> subs = s.getSubscriptions();
assertEquals(2, subs.size()); assertEquals(2, subs.size());
assertEquals(Long.valueOf(0L), subs.get(group)); assertEquals(Long.valueOf(0L), subs.get(group));
@@ -242,8 +242,8 @@ public class ProtocolIntegrationTest extends TestCase {
assertTrue(s.getTimestamp() == timestamp); assertTrue(s.getTimestamp() == timestamp);
// Read the transport update // Read the transport update
assertTrue(protocolReader.hasTransportUpdate()); assertTrue(reader.hasTransportUpdate());
TransportUpdate t = protocolReader.readTransportUpdate(); TransportUpdate t = reader.readTransportUpdate();
assertEquals(transports, t.getTransports()); assertEquals(transports, t.getTransports());
assertTrue(t.getTimestamp() == timestamp); assertTrue(t.getTimestamp() == timestamp);

View File

@@ -84,7 +84,8 @@ public class ConstantsTest extends TestCase {
private void testBatchesFitIntoAck(int length) throws Exception { private void testBatchesFitIntoAck(int length) throws Exception {
// Create an ack with as many batch IDs as possible // Create an ack with as many batch IDs as possible
ByteArrayOutputStream out = new ByteArrayOutputStream(length); ByteArrayOutputStream out = new ByteArrayOutputStream(length);
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out); ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out,
true);
int maxBatches = writer.getMaxBatchesForAck(length); int maxBatches = writer.getMaxBatchesForAck(length);
Collection<BatchId> acked = new ArrayList<BatchId>(); Collection<BatchId> acked = new ArrayList<BatchId>();
for(int i = 0; i < maxBatches; i++) { for(int i = 0; i < maxBatches; i++) {
@@ -116,7 +117,8 @@ public class ConstantsTest extends TestCase {
// Add the message to a batch // Add the message to a batch
ByteArrayOutputStream out = ByteArrayOutputStream out =
new ByteArrayOutputStream(MAX_PACKET_LENGTH); new ByteArrayOutputStream(MAX_PACKET_LENGTH);
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out); ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out,
true);
RawBatch b = packetFactory.createBatch(Collections.singletonList( RawBatch b = packetFactory.createBatch(Collections.singletonList(
message.getSerialised())); message.getSerialised()));
writer.writeBatch(b); writer.writeBatch(b);
@@ -140,7 +142,8 @@ public class ConstantsTest extends TestCase {
private void testMessagesFitIntoOffer(int length) throws Exception { private void testMessagesFitIntoOffer(int length) throws Exception {
// Create an offer with as many message IDs as possible // Create an offer with as many message IDs as possible
ByteArrayOutputStream out = new ByteArrayOutputStream(length); ByteArrayOutputStream out = new ByteArrayOutputStream(length);
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out); ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out,
true);
int maxMessages = writer.getMaxMessagesForOffer(length); int maxMessages = writer.getMaxMessagesForOffer(length);
Collection<MessageId> offered = new ArrayList<MessageId>(); Collection<MessageId> offered = new ArrayList<MessageId>();
for(int i = 0; i < maxMessages; i++) { for(int i = 0; i < maxMessages; i++) {
@@ -165,7 +168,8 @@ public class ConstantsTest extends TestCase {
// Add the subscriptions to an update // Add the subscriptions to an update
ByteArrayOutputStream out = ByteArrayOutputStream out =
new ByteArrayOutputStream(MAX_PACKET_LENGTH); new ByteArrayOutputStream(MAX_PACKET_LENGTH);
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out); ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out,
true);
SubscriptionUpdate s = packetFactory.createSubscriptionUpdate(subs, SubscriptionUpdate s = packetFactory.createSubscriptionUpdate(subs,
Long.MAX_VALUE); Long.MAX_VALUE);
writer.writeSubscriptionUpdate(s); writer.writeSubscriptionUpdate(s);
@@ -194,7 +198,8 @@ public class ConstantsTest extends TestCase {
// Add the transports to an update // Add the transports to an update
ByteArrayOutputStream out = ByteArrayOutputStream out =
new ByteArrayOutputStream(MAX_PACKET_LENGTH); new ByteArrayOutputStream(MAX_PACKET_LENGTH);
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out); ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out,
true);
TransportUpdate t = packetFactory.createTransportUpdate(transports, TransportUpdate t = packetFactory.createTransportUpdate(transports,
Long.MAX_VALUE); Long.MAX_VALUE);
writer.writeTransportUpdate(t); writer.writeTransportUpdate(t);

View File

@@ -80,7 +80,7 @@ public class ProtocolReadWriteTest extends TestCase {
public void testWriteAndRead() throws Exception { public void testWriteAndRead() throws Exception {
// Write // Write
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
ProtocolWriter writer = writerFactory.createProtocolWriter(out); ProtocolWriter writer = writerFactory.createProtocolWriter(out, true);
Ack a = packetFactory.createAck(Collections.singletonList(batchId)); Ack a = packetFactory.createAck(Collections.singletonList(batchId));
writer.writeAck(a); writer.writeAck(a);

View File

@@ -37,7 +37,8 @@ public class ProtocolWriterImplTest extends TestCase {
@Test @Test
public void testWriteBitmapNoPadding() throws IOException { public void testWriteBitmapNoPadding() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
ProtocolWriter w = new ProtocolWriterImpl(serial, writerFactory, out); ProtocolWriter w = new ProtocolWriterImpl(serial, writerFactory, out,
true);
BitSet b = new BitSet(); BitSet b = new BitSet();
// 11011001 = 0xD9 // 11011001 = 0xD9
b.set(0); b.set(0);
@@ -61,7 +62,8 @@ public class ProtocolWriterImplTest extends TestCase {
@Test @Test
public void testWriteBitmapWithPadding() throws IOException { public void testWriteBitmapWithPadding() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
ProtocolWriter w = new ProtocolWriterImpl(serial, writerFactory, out); ProtocolWriter w = new ProtocolWriterImpl(serial, writerFactory, out,
true);
BitSet b = new BitSet(); BitSet b = new BitSet();
// 01011001 = 0x59 // 01011001 = 0x59
b.set(1); b.set(1);

View File

@@ -112,7 +112,7 @@ public class BatchConnectionReadWriteTest extends TestCase {
ProtocolWriterFactory protoFactory = ProtocolWriterFactory protoFactory =
alice.getInstance(ProtocolWriterFactory.class); alice.getInstance(ProtocolWriterFactory.class);
TestBatchTransportWriter transport = new TestBatchTransportWriter(out, TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
Long.MAX_VALUE); Long.MAX_VALUE, false);
OutgoingBatchConnection batchOut = new OutgoingBatchConnection(db, OutgoingBatchConnection batchOut = new OutgoingBatchConnection(db,
connFactory, protoFactory, contactId, transportIndex, connFactory, protoFactory, contactId, transportIndex,
transport); transport);

View File

@@ -73,7 +73,7 @@ public class OutgoingBatchConnectionTest extends TestCase {
public void testConnectionTooShort() throws Exception { public void testConnectionTooShort() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
TestBatchTransportWriter transport = new TestBatchTransportWriter(out, TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
ProtocolConstants.MAX_PACKET_LENGTH); ProtocolConstants.MAX_PACKET_LENGTH, true);
OutgoingBatchConnection connection = new OutgoingBatchConnection(db, OutgoingBatchConnection connection = new OutgoingBatchConnection(db,
connFactory, protoFactory, contactId, transportIndex, connFactory, protoFactory, contactId, transportIndex,
transport); transport);
@@ -97,7 +97,7 @@ public class OutgoingBatchConnectionTest extends TestCase {
public void testNothingToSend() throws Exception { public void testNothingToSend() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
TestBatchTransportWriter transport = new TestBatchTransportWriter(out, TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
TransportConstants.MIN_CONNECTION_LENGTH); TransportConstants.MIN_CONNECTION_LENGTH, true);
OutgoingBatchConnection connection = new OutgoingBatchConnection(db, OutgoingBatchConnection connection = new OutgoingBatchConnection(db,
connFactory, protoFactory, contactId, transportIndex, connFactory, protoFactory, contactId, transportIndex,
transport); transport);
@@ -133,7 +133,7 @@ public class OutgoingBatchConnectionTest extends TestCase {
public void testSomethingToSend() throws Exception { public void testSomethingToSend() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
TestBatchTransportWriter transport = new TestBatchTransportWriter(out, TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
TransportConstants.MIN_CONNECTION_LENGTH); TransportConstants.MIN_CONNECTION_LENGTH, true);
OutgoingBatchConnection connection = new OutgoingBatchConnection(db, OutgoingBatchConnection connection = new OutgoingBatchConnection(db,
connFactory, protoFactory, contactId, transportIndex, connFactory, protoFactory, contactId, transportIndex,
transport); transport);

View File

@@ -9,12 +9,15 @@ class TestBatchTransportWriter implements BatchTransportWriter {
private final ByteArrayOutputStream out; private final ByteArrayOutputStream out;
private final long capacity; private final long capacity;
private final boolean flush;
private boolean disposed = false, exception = false; private boolean disposed = false, exception = false;
TestBatchTransportWriter(ByteArrayOutputStream out, long capacity) { TestBatchTransportWriter(ByteArrayOutputStream out, long capacity,
boolean flush) {
this.out = out; this.out = out;
this.capacity = capacity; this.capacity = capacity;
this.flush = flush;
} }
public long getCapacity() { public long getCapacity() {
@@ -25,6 +28,10 @@ class TestBatchTransportWriter implements BatchTransportWriter {
return out; return out;
} }
public boolean shouldFlush() {
return flush;
}
public void dispose(boolean exception) { public void dispose(boolean exception) {
assert !disposed; assert !disposed;
disposed = true; disposed = true;