package com.nvarghese.beowulf.common.cobra.html.js;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Scriptable;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import com.nvarghese.beowulf.common.cobra.html.HttpRequest;
import com.nvarghese.beowulf.common.cobra.html.ReadyStateChangeListener;
import com.nvarghese.beowulf.common.cobra.html.UserAgentContext;
import com.nvarghese.beowulf.common.cobra.js.AbstractScriptableDelegate;
import com.nvarghese.beowulf.common.cobra.js.JavaScript;
import com.nvarghese.beowulf.common.cobra.util.Urls;
public class XMLHttpRequest extends AbstractScriptableDelegate {
// TODO: See reference:
// https://developer.mozilla.org/en/xmlhttprequest
// http://www.w3.org/TR/XMLHttpRequest/#the-xmlhttprequest-interface
private static final Logger logger = Logger.getLogger(XMLHttpRequest.class.getName());
private final HttpRequest request;
private final UserAgentContext pcontext;
private final Scriptable scope;
private final java.net.URL codeSource;
public XMLHttpRequest(UserAgentContext pcontext, java.net.URL codeSource, Scriptable scope) {
this.request = pcontext.createHttpRequest();
this.pcontext = pcontext;
this.scope = scope;
this.codeSource = codeSource;
}
public void abort() {
request.abort();
}
public String getAllResponseHeaders() {
return request.getAllResponseHeaders();
}
public int getReadyState() {
return request.getReadyState();
}
public byte[] getResponseBytes() {
return request.getResponseBytes();
}
public String getResponseHeader(String headerName) {
return request.getResponseHeader(headerName);
}
public String getResponseText() {
return request.getResponseText();
}
public Document getResponseXML() {
return request.getResponseXML();
}
public int getStatus() {
return request.getStatus();
}
public String getStatusText() {
return request.getStatusText();
}
public void setRequestHeader(String headerName, String value) {
if (request.getReadyState() == HttpRequest.STATE_LOADING && !request.wasSend()) {
request.setRequestHeader(headerName, value);
} else {
throw new DOMException(DOMException.INVALID_STATE_ERR, "Invalid state while setting header");
}
}
private URL getFullURL(String relativeUrl) throws java.net.MalformedURLException {
return Urls.createURL(this.codeSource, relativeUrl);
}
public void open(String method, String url, boolean asyncFlag, String userName, String password) throws java.io.IOException {
request.open(method, this.getFullURL(url), asyncFlag, userName, password);
}
public void open(String method, String url, boolean asyncFlag, String userName) throws java.io.IOException {
request.open(method, this.getFullURL(url), asyncFlag, userName);
}
public void open(String method, String url, boolean asyncFlag) throws java.io.IOException {
request.open(method, this.getFullURL(url), asyncFlag);
}
public void open(String method, String url) throws java.io.IOException {
request.open(method, this.getFullURL(url));
}
public void send(String content) throws java.io.IOException {
request.send(content);
}
private Function onreadystatechange;
private boolean listenerAdded;
public Function getOnreadystatechange() {
synchronized (this) {
return this.onreadystatechange;
}
}
public void setOnreadystatechange(final Function value) {
synchronized (this) {
this.onreadystatechange = value;
if (value != null && !this.listenerAdded) {
this.request.addReadyStateChangeListener(new ReadyStateChangeListener() {
public void readyStateChanged() {
// Not called in GUI thread to ensure consistency of
// readyState.
executeReadyStateChange();
}
});
this.listenerAdded = true;
}
}
}
private void executeReadyStateChange() {
// Not called in GUI thread to ensure consistency of readyState.
try {
Function f = XMLHttpRequest.this.getOnreadystatechange();
if (f != null) {
Context ctx = Executor.createContext(this.codeSource, this.pcontext);
try {
Scriptable newScope = (Scriptable) JavaScript.getInstance().getJavascriptObject(XMLHttpRequest.this, this.scope);
f.call(ctx, newScope, newScope, new Object[0]);
} finally {
Context.exit();
}
}
} catch (Exception err) {
logger.log(Level.WARNING, "Error processing ready state change.", err);
}
}
}