/*******************************************************************************
* Copyright (c) 2012-2015 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.rest;
import org.eclipse.che.ide.commons.exception.JobNotFoundException;
import org.eclipse.che.ide.commons.exception.ServerException;
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.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window.Location;
/** Wrapper under RequestBuilder to simplify the stuffs. */
public class AsyncRequest {
protected RequestBuilder builder;
protected AsyncRequestLoader loader;
protected boolean async;
protected String loaderMessage;
protected int delay = 5000;
protected RequestStatusHandler handler;
protected String requestStatusUrl;
private AsyncRequestCallback<?> callback;
private AsyncRequestCallback<String> initCallback = new AsyncRequestCallback<String>(new LocationUnmarshaller()) {
{
setSuccessCodes(new int[]{Response.SC_ACCEPTED});
}
@Override
protected void onSuccess(String result) {
requestStatusUrl = result;
if (handler != null) {
handler.requestInProgress(requestStatusUrl);
}
requestTimer.schedule(delay);
}
@Override
protected void onFailure(Throwable exception) {
if (handler != null) {
handler.requestError(requestStatusUrl, exception);
}
callback.onError(null, exception);
}
};
private Timer requestTimer = new Timer() {
@Override
public void run() {
RequestBuilder request = new RequestBuilder(RequestBuilder.GET, requestStatusUrl);
request.setCallback(new RequestCallback() {
public void onResponseReceived(Request request, Response response) {
if (Response.SC_NOT_FOUND == response.getStatusCode()) {
callback.onError(request, new JobNotFoundException(response));
if (handler != null) {
handler.requestError(requestStatusUrl, new JobNotFoundException(response));
}
} else if (response.getStatusCode() != Response.SC_ACCEPTED) {
callback.onResponseReceived(request, response);
if (handler != null) {
// check is response successful, for correct handling failed responses
if (callback.isSuccessful(response))
handler.requestFinished(requestStatusUrl);
else
handler.requestError(requestStatusUrl, new ServerException(response));
}
} else {
if (handler != null)
handler.requestInProgress(requestStatusUrl);
requestTimer.schedule(delay);
}
}
public void onError(Request request, Throwable exception) {
if (handler != null)
handler.requestError(requestStatusUrl, exception);
callback.onError(request, exception);
}
});
try {
request.send();
} catch (RequestException e) {
e.printStackTrace();
if (handler != null) {
handler.requestError(requestStatusUrl, e);
}
callback.onFailure(e);
}
}
};
/**
* Create new {@link AsyncRequest} instance.
*
* @param method
* request method
* @param url
* request URL
* @param async
* if <b>true</b> - request will be sent in asynchronous mode
*/
protected AsyncRequest(Method method, String url, boolean async) {
if (async) {
if (url.contains("?")) {
url += "&async=true";
} else {
url += "?async=true";
}
}
this.builder = new RequestBuilder(method, getCheckedURL(url));
this.loader = new EmptyLoader();
this.async = async;
}
/** @deprecated use {@link AsyncRequestFactory} instead. */
@Deprecated
protected AsyncRequest(RequestBuilder builder) {
this.builder = builder;
this.loader = new EmptyLoader();
async = false;
}
/** @deprecated use {@link AsyncRequestFactory} instead. */
@Deprecated
protected AsyncRequest(RequestBuilder builder, boolean async) {
this(builder);
this.async = async;
}
private static native String getProxyServiceContext() /*-{
return $wnd.proxyServiceContext;
}-*/;
private static String getCheckedURL(String url) {
String proxyServiceContext = getProxyServiceContext();
if (proxyServiceContext == null || "".equals(proxyServiceContext)) {
return url;
}
if (!(url.startsWith("http://") || url.startsWith("https://"))) {
return url;
}
String currentHost = Location.getProtocol() + "//" + Location.getHost();
if (url.startsWith(currentHost)) {
return url;
}
return proxyServiceContext + "?url=" + URL.encodeQueryString(url);
}
/** @deprecated use {@link AsyncRequestFactory} instead. */
@Deprecated
public static final AsyncRequest build(Method method, String url) {
return build(method, url, false);
}
/**
* Build AsyncRequest with run REST Service in async mode.
*
* @param method
* HTTP method
* @param url
* of service
* @param async
* is run async
* @return instance of {@link AsyncRequest}
* @deprecated use {@link AsyncRequestFactory} instead.
*/
@Deprecated
public static final AsyncRequest build(Method method, String url, boolean async) {
if (async) {
if (url.contains("?")) {
url += "&async=true";
} else {
url += "?async=true";
}
}
String checkedURL = getCheckedURL(url);
return new AsyncRequest(new RequestBuilder(method, checkedURL), async);
}
public final AsyncRequest header(String header, String value) {
builder.setHeader(header, value);
return this;
}
public final AsyncRequest user(String user) {
builder.setUser(user);
return this;
}
public final AsyncRequest password(String password) {
builder.setPassword(password);
return this;
}
public final AsyncRequest data(String requestData) {
builder.setRequestData(requestData);
return this;
}
public final AsyncRequest loader(AsyncRequestLoader loader) {
this.loader = loader;
return this;
}
public final AsyncRequest loader(AsyncRequestLoader loader, String loaderMessage) {
this.loader = loader;
this.loaderMessage = loaderMessage;
return this;
}
/**
* Set delay between requests to async REST Service<br>
* (Default: 5000 ms).
*
* @param delay
* the amount of time to wait between request resending (in milliseconds)
* @return this {@code AsyncRequest}
*/
public final AsyncRequest delay(int delay) {
this.delay = delay;
return this;
}
/**
* Set handler of async REST Service status.
*
* @param handler
* @return
*/
public final AsyncRequest requestStatusHandler(RequestStatusHandler handler) {
this.handler = handler;
return this;
}
private void sendRequest(AsyncRequestCallback<?> callback) throws RequestException {
callback.setLoader(loader, loaderMessage);
callback.setRequest(this);
builder.setCallback(callback);
if (loaderMessage == null) {
loader.show();
} else {
loader.show(loaderMessage);
}
builder.send();
}
/**
* Sends an HTTP request based on the current {@link AsyncRequest} configuration.
*
* @param callback
* the response handler to be notified when the request fails or completes
*/
public final void send(AsyncRequestCallback<?> callback) {
this.callback = callback;
try {
if (async) {
sendRequest(initCallback);
} else {
sendRequest(callback);
}
} catch (RequestException e) {
callback.onFailure(e);
}
}
/**
* Returns the callback of current {@link AsyncRequest}, or null if no callback was set.
*
* @return the callback that to be notified when the request fails or completes
*/
public AsyncRequestCallback<?> getCallback() {
return callback;
}
private class EmptyLoader implements AsyncRequestLoader {
@Override
public void hide() {
}
@Override
public void hide(String message) {
}
@Override
public void show() {
}
@Override
public void show(String message) {
}
}
}