package er.extensions.appserver;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webobjects.foundation.NSForwardException;
/**
* Special response that keeps the connection alive and pushes the data to
* the client. It does this by opening a stream that has small buffer but
* huge length.
*
* @author ak
*/
public class ERXKeepAliveResponse extends ERXResponse {
private static final Logger log = LoggerFactory.getLogger(ERXKeepAliveResponse.class);
/**
* Queue to push the items into.
*/
protected Queue<byte[]> _queue = new ConcurrentLinkedQueue<>();
/**
* Current data to write to client.
*/
protected byte[] _current = null;
/**
* Current index in
*/
protected int _currentIndex = 0;
public ERXKeepAliveResponse() {
//setHeader("keep-alive", "connection");
setContentStream(new InputStream() {
@Override
public int read() throws IOException {
synchronized (_queue) {
if (_current != null && _currentIndex >= _current.length) {
_current = null;
_currentIndex = 0;
}
if (_current == null) {
try {
if (log.isDebugEnabled()) {
log.debug("waiting: {}", _queue.hashCode());
}
_queue.wait();
if (log.isDebugEnabled()) {
log.debug("got data: {}", _queue.hashCode());
}
}
catch (InterruptedException e) {
return -1;
}
_current = _queue.poll();
}
if (_current == null) {
return -1;
}
log.debug("writing: {}", _currentIndex);
return _current[_currentIndex++];
}
}
}, 1, Long.MAX_VALUE); // MS: turning it up to 11
}
/**
* Enqueues the data for this string using the response encoding.
*
* @param str the string to push
*/
public void push(String str) {
try {
push(str.getBytes(contentEncoding()));
}
catch (UnsupportedEncodingException e) {
throw NSForwardException._runtimeExceptionForThrowable(e);
}
}
/**
* Enqueues the data.
*
* @param data
*/
public void push(byte[] data) {
if (log.isDebugEnabled()) {
log.debug("pushing: " + _queue.hashCode());
}
synchronized (_queue) {
_queue.offer(data);
_queue.notify();
}
}
/**
* Resets the response by clearing out the current item and notifying
* the queue.
*/
public void reset() {
synchronized (_queue) {
_current = null;
_currentIndex = 0;
_queue.notify();
}
}
}