/**
* $RCSfile: $
* $Revision: $
* $Date: $
*
* Copyright (C) 2006 Jive Software. All rights reserved.
* This software is the proprietary information of Jive Software. Use is subject to license terms.
*/
package org.jivesoftware.multiplexer.net.http;
import org.jivesoftware.multiplexer.Connection;
import org.mortbay.util.ajax.Continuation;
/**
* A connection to a client. The client will wait on getDeliverable() until the server forwards a
* message to it or the wait time on the session timesout.
*
* @author Alexander Wenckus
*/
public class HttpConnection {
private Connection.CompressionPolicy compressionPolicy;
private long requestId;
private String body;
private HttpSession session;
private Continuation continuation;
private boolean isClosed;
private boolean isSecure = false;
public HttpConnection(long requestId, boolean isSecure) {
this.requestId = requestId;
this.isSecure = isSecure;
}
public boolean validate() {
return false;
}
/**
* The connection should be closed without delivering a stanza to the requestor.
*/
public void close() {
if (isClosed) {
return;
}
try {
deliverBody(null);
}
catch (HttpConnectionClosedException e) {
/* Shouldn't happen */
}
}
public boolean isClosed() {
return isClosed;
}
public boolean isSecure() {
return isSecure;
}
/**
* Delivers content to the client. The content should be valid XMPP wrapped inside of a body.
* A <i>null</i> value for body indicates that the connection should be closed and the client
* sent an empty body.
*
* @param body the XMPP content to be forwarded to the client inside of a body tag.
*
* @throws HttpConnectionClosedException when this connection to the client has already recieved
* a deliverable to forward to the client
*/
public void deliverBody(String body) throws HttpConnectionClosedException {
// We only want to use this function once so we will close it when the body is delivered.
if (isClosed) {
throw new HttpConnectionClosedException("The http connection is no longer " +
"available to deliver content");
}
else {
isClosed = true;
}
if (continuation != null) {
continuation.setObject(body);
continuation.resume();
}
else {
this.body = body;
}
}
/**
* A call that will cause a wait, or in the case of Jetty the thread to be freed, if there is no
* deliverable currently available. Once the deliverable becomes available it is returned.
*
* @return the deliverable to send to the client
*
* @throws HttpBindTimeoutException to indicate that the maximum wait time requested by the
* client has been surpassed and an empty response should be returned.
*/
public String getDeliverable() throws HttpBindTimeoutException {
if (body == null && continuation != null) {
try {
body = waitForDeliverable();
}
catch (HttpBindTimeoutException e) {
this.isClosed = true;
throw e;
}
}
else if (body == null) {
throw new IllegalStateException("Continuation not set, cannot wait for deliverable.");
}
return body;
}
private String waitForDeliverable() throws HttpBindTimeoutException {
if (continuation.suspend(session.getWait() * 1000)) {
String deliverable = (String) continuation.getObject();
// This will occur when the hold attribute of a session has been exceded.
if (deliverable == null) {
throw new HttpBindTimeoutException();
}
return deliverable;
}
throw new HttpBindTimeoutException("Request " + requestId + " exceded response time from " +
"server of " + session.getWait() + " seconds.");
}
public boolean isCompressed() {
return false;
}
public Connection.CompressionPolicy getCompressionPolicy() {
return compressionPolicy;
}
public void setCompressionPolicy(Connection.CompressionPolicy compressionPolicy) {
this.compressionPolicy = compressionPolicy;
}
public long getRequestId() {
return requestId;
}
/**
* Set the session that this connection belongs to.
*
* @param session the session that this connection belongs to.
*/
void setSession(HttpSession session) {
this.session = session;
}
/**
* Returns the session that this connection belongs to.
*
* @return the session that this connection belongs to.
*/
public HttpSession getSession() {
return session;
}
void setContinuation(Continuation continuation) {
this.continuation = continuation;
}
}