/** * Constructor for the <code>SocketBufferWriter</code> object. This * is used to create a writer that can write buffers to the socket * in such a way that it write either asynchronously or block * the calling thread until such time as the buffers are written. * * @param socket this is the pipeline that this writes to * @param reactor this is the writer used to scheduler writes * @param buffer this is the initial size of the output buffer * @param threshold this is the maximum size of the buffer */ public SocketBufferWriter(Socket socket, Reactor reactor, int buffer, int threshold) throws IOException { this.writer = new SocketBuffer(socket, buffer, threshold); this.flusher = new SocketFlusher(writer, socket, reactor); }
/** * This is used to abort the flushing process when the reactor has * been stopped. An abort to the flusher typically happens when the * server has been shutdown. It prevents threads lingering waiting * for a I/O operation which prevents the server from shutting down. */ public synchronized void abort() throws IOException { scheduler.close(); buffer.close(); }
/** * This method is used to flush all of the queued buffers to * the client. This method will not block but will simply flush * any data to the underlying transport. Internally the data * will be queued for delivery to the connected entity. */ public void flush() throws IOException { boolean done = writer.flush(); // returns true only if everything is delivered if(!done) { flusher.flush(); // here we will block for an op write event if the buffer contains a reference } }
/** * This is executed when the flusher is to write all of the data to * the underlying socket. In this situation the writes are attempted * in a non blocking way, if the task does not complete then this * will simply enqueue the writing task for OP_WRITE and leave the * method. This returns true if all the buffers are written. */ public synchronized void execute() throws IOException { boolean ready = buffer.flush(); if(!ready) { boolean block = !buffer.ready(); if(!block && !closed) { scheduler.release(); } scheduler.repeat(); } else{ scheduler.ready(); } }
/** * This method is used to deliver the provided buffer of bytes to * the underlying transport. This will not modify the data that * is to be written, this will simply queue the buffers in the * order that they are provided. * * @param buffer this is the array of bytes to send to the client */ public void write(ByteBuffer buffer) throws IOException { boolean done = writer.write(buffer); // returns true if we can buffer if(!done) { flusher.flush(); // we could not fully write or buffer the data so we must flush } }
/** * Here in this method we schedule a flush when the underlying * writer is write ready. This allows the writer thread to return * without having to fully flush the content to the underlying * transport. If there are references queued this will block. */ public synchronized void flush() throws IOException { if(closed) { throw new TransportException("Flusher is closed"); } boolean block = !buffer.ready(); if(!closed) { scheduler.schedule(block); } }
/** * This is executed when the flusher is to write all of the data to * the underlying socket. In this situation the writes are attempted * in a non blocking way, if the task does not complete then this * will simply enqueue the writing task for OP_WRITE and leave the * method. This returns true if all the buffers are written. */ public synchronized void execute() throws IOException { boolean ready = buffer.flush(); if(!ready) { boolean block = !buffer.ready(); if(!block && !closed) { scheduler.release(); } scheduler.repeat(); } else{ scheduler.ready(); } }
/** * This method is used to deliver the provided buffer of bytes to * the underlying transport. This will not modify the data that * is to be written, this will simply queue the buffers in the * order that they are provided. * * @param buffer this is the array of bytes to send to the client */ public void write(ByteBuffer buffer) throws IOException { boolean done = writer.write(buffer); // returns true if we can buffer if(!done) { flusher.flush(); // we could not fully write or buffer the data so we must flush } }
/** * Here in this method we schedule a flush when the underlying * writer is write ready. This allows the writer thread to return * without having to fully flush the content to the underlying * transport. If there are references queued this will block. */ public synchronized void flush() throws IOException { if(closed) { throw new TransportException("Flusher is closed"); } boolean block = !buffer.ready(); if(!closed) { scheduler.schedule(block); } }
/** * This is used to close the writer and the underlying socket. * If a close is performed on the writer then no more bytes * can be read from or written to the writer and the client * will receive a connection close on their side. */ public void close() throws IOException { flusher.close(); writer.close(); } }
/** * This method is used to flush all of the queued buffers to * the client. This method will not block but will simply flush * any data to the underlying transport. Internally the data * will be queued for delivery to the connected entity. */ public void flush() throws IOException { boolean done = writer.flush(); // returns true only if everything is delivered if(!done) { flusher.flush(); // here we will block for an op write event if the buffer contains a reference } }
/** * This method is used to perform a merge of the buffer to be sent * with the current buffer. If the internal buffer is large enough * to send after the merge then it will be sent. Also, if the * remaining bytes in the buffer are large enough for a packet * then that too will be sent over the socket. * * @param duplicate this is the buffer to be merged * * @return this returns true if no reference was held */ private synchronized boolean merge(ByteBuffer duplicate) throws IOException { if(closed) { throw new TransportException("Buffer has been closed"); } int count = appender.length(); int merged = appender.append(duplicate); int payload = merged + count; if(payload >= chunk) { // viable packet size int written = appender.write(channel); if(written < payload) {// count not fully flush buffer reference = duplicate; return false; } return write(duplicate); // we are back at zero } return true; // everything was buffered as chunk >= capacity }
/** * Constructor for the <code>SocketBufferWriter</code> object. This * is used to create a writer that can write buffers to the socket * in such a way that it write either asynchronously or block * the calling thread until such time as the buffers are written. * * @param socket this is the pipeline that this writes to * @param reactor this is the writer used to scheduler writes * @param buffer this is the initial size of the output buffer * @param threshold this is the maximum size of the buffer */ public SocketBufferWriter(Socket socket, Reactor reactor, int buffer, int threshold) throws IOException { this.writer = new SocketBuffer(socket, buffer, threshold); this.flusher = new SocketFlusher(writer, socket, reactor); }
/** * This is used to abort the flushing process when the reactor has * been stopped. An abort to the flusher typically happens when the * server has been shutdown. It prevents threads lingering waiting * for a I/O operation which prevents the server from shutting down. */ public synchronized void abort() throws IOException { scheduler.close(); buffer.close(); }
/** * This is used to close the flusher ensuring that all of the * data within the writer will be flushed regardless of the * amount of data within the writer that needs to be written. If * the writer does not block then this waits to be finished. */ public synchronized void close() throws IOException { boolean ready = buffer.flush(); if(!closed) { closed = true; } if(!ready) { scheduler.schedule(true); } } }
/** * This method is used to perform a merge of the buffer to be sent * with the current buffer. If the internal buffer is large enough * to send after the merge then it will be sent. Also, if the * remaining bytes in the buffer are large enough for a packet * then that too will be sent over the socket. * * @param duplicate this is the buffer to be merged * * @return this returns true if no reference was held */ private synchronized boolean merge(ByteBuffer duplicate) throws IOException { if(closed) { throw new TransportException("Buffer has been closed"); } int count = appender.length(); int merged = appender.append(duplicate); int payload = merged + count; if(payload >= chunk) { // viable packet size int written = appender.write(channel); if(written < payload) {// count not fully flush buffer reference = duplicate; return false; } return write(duplicate); // we are back at zero } return true; // everything was buffered as chunk >= capacity }