/**
*
*/
package xapi.gwt.io;
import xapi.annotation.inject.SingletonOverride;
import xapi.collect.X_Collect;
import xapi.collect.api.Dictionary;
import xapi.collect.api.StringDictionary;
import xapi.collect.api.StringTo;
import xapi.collect.api.StringTo.Many;
import xapi.inject.impl.SingletonProvider;
import xapi.io.IOConstants;
import xapi.io.api.CancelledException;
import xapi.io.api.IOCallback;
import xapi.io.api.IOMessage;
import xapi.io.api.IORequest;
import xapi.io.impl.AbstractIOService;
import xapi.io.service.IOService;
import xapi.log.X_Log;
import xapi.log.api.LogLevel;
import xapi.platform.GwtPlatform;
import xapi.time.X_Time;
import xapi.time.api.Moment;
import xapi.util.X_Runtime;
import xapi.util.api.ReceivesValue;
import com.google.gwt.core.client.GWT;
import com.google.gwt.http.client.Header;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestBuilder.Method;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.Response;
import javax.inject.Provider;
/**
* @author James X. Nelson (james@wetheinter.net, @james)
*
*/
@SingletonOverride(implFor=IOService.class)
@GwtPlatform
public class IOServiceGwt extends AbstractIOService <RequestBuilder> {
/**
* @author James X. Nelson (james@wetheinter.net, @james)
*
*/
public class IORequestGwt extends AbstractIORequest {
private Request request;
@Override
public void cancel() {
super.cancel();
if (request != null) {
request.cancel();
}
}
@Override
public String response() {
return getValue();
}
public void setRequest(final Request request) {
this.request = request;
}
}
protected RequestBuilder newRequest(final Method method, final String url) {
return new RequestBuilder(method, url);
}
@Override
public IORequest<String> get(final String uri, final StringDictionary<String> headers, final IOCallback<IOMessage<String>> callback) {
final String url = normalize(uri);
if (callback.isCancelled()) {
return cancelled;
}
try {
final RequestBuilder request = newRequest(RequestBuilder.GET, url);
normalizeHeaders(headers).forKeys(new ReceivesValue<String>() {
@Override
public void set(final String key) {
final String value = headers.getValue(key);
request.setHeader(key, value);
}
});
applySettings(request, IOConstants.METHOD_GET);
final IORequestGwt req = createRequest();
sendRequest(request, req, callback, url, headers, IOConstants.METHOD_GET, null);
return req;
} catch (final Throwable e) {
callback.onError(e);
if (X_Runtime.isDebug()) {
X_Log.warn("IO Error", e);
}
return cancelled;
}
}
/**
* @see xapi.io.service.IOService#post(java.lang.String, java.lang.String, xapi.collect.api.StringDictionary, xapi.io.api.IOCallback)
*/
@Override
public IORequest<String> post(final String uri, final String body, final StringDictionary<String> headers,
final IOCallback<IOMessage<String>> callback) {
final String url = normalize(uri);
if (callback.isCancelled()) {
return cancelled;
}
try {
final RequestBuilder request = newRequest(RequestBuilder.POST, url);
normalizeHeaders(headers).forKeys(new ReceivesValue<String>() {
@Override
public void set(final String key) {
final String value = headers.getValue(key);
assert value != null : "Cannot set a null header value for "+key+"; url: "+url;
request.setHeader(key, value);
}
});
applySettings(request, IOConstants.METHOD_POST);
final IORequestGwt req = createRequest();
sendRequest(request, req, callback, url, headers, IOConstants.METHOD_POST, body);
return req;
} catch (final Throwable e) {
callback.onError(e);
if (X_Runtime.isDebug()) {
X_Log.warn("IO Error", e);
}
return cancelled;
}
}
protected Dictionary<String, String> normalizeHeaders(StringDictionary<String> headers) {
if (headers == null) {
headers = X_Collect.newDictionary();
}
if (!headers.hasKey("X-Gwt-Version")) {
headers.setValue("X-Gwt-Version", GWT.getPermutationStrongName());
}
if (!headers.hasKey("X-Gwt-Module")) {
headers.setValue("X-Gwt-Module", GWT.getModuleName());
}
return headers;
}
protected void sendRequest(final RequestBuilder req, final IORequestGwt request, final IOCallback<IOMessage<String>> callback, final String url, final StringDictionary<String> headers, final int method, final String body) {
final LogLevel logLevel = logLevel();
request.start();
try {
final Request r = req.sendRequest(body, new RequestCallback() {
@Override
public void onResponseReceived(final Request req, final Response resp) {
if (request.isCancelled()) {
callback.onError(new CancelledException(request));
return;
}
final Provider<Many<String>> resultHeaders = new SingletonProvider<Many<String>>() {
@Override
protected Many<String> initialValue() {
final Many<String> headers = X_Collect.newStringMultiMap(String.class);
for (final Header header : resp.getHeaders()) {
headers.add(header.getName(), header.getValue());
}
return headers;
}
};
request.setStatus(resp.getStatusCode(), resp.getStatusText());
request.setValue(resp.getText());
request.setResultHeaders(resultHeaders);
final Moment callbackTime = X_Time.now();
try {
callback.onSuccess(new IOMessage<String>() {
@Override
public String body() {
return request.getValue();
}
@Override
public int modifier() {
return method;
}
@Override
public String url() {
return url;
}
@Override
public int statusCode() {
return resp.getStatusCode();
}
@Override
public String statusMessage() {
return resp.getStatusText();
};
@Override
public StringTo.Many<String> headers() {
return resultHeaders.get();
}
});
} catch (final Throwable t) {
X_Log.error("Error invoking IO callback on",callback,"for request",url, t, t.getStackTrace());
callback.onError(t);
}
if (X_Log.loggable(logLevel)) {
X_Log.log(getClass(), logLevel, "Callback time for ",url,"took",X_Time.difference(callbackTime));
}
}
@Override
public void onError(final Request request, final Throwable exception) {
callback.onError(exception);
}
});
request.setRequest(r);
} catch (final Throwable e) {
callback.onError(e);
if (X_Runtime.isDebug()) {
X_Log.error(getClass(), "Error sending request",url,e);
}
}
}
protected IORequestGwt createRequest() {
return new IORequestGwt();
}
@Override
protected native String uriBase()
/*-{
if (!$wnd.location.origin) {
if ($wnd.location.port === 80 || $wnd.location.port === 443) {
$wnd.location.origin = $wnd.location.host;
} else {
$wnd.location.origin = $wnd.location.host + ":" + $wnd.location.port;
}
}
return $wnd.location.origin;
}-*/;
}