package com.asayama.gwt.angular.http.client;
import com.asayama.gwt.angular.client.Injector;
import com.asayama.gwt.angular.client.Service;
import com.asayama.gwt.angular.client.q.Deferred;
import com.asayama.gwt.angular.client.q.Promise;
import com.asayama.gwt.angular.client.q.Q;
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;
/**
* Provides HTTP client implementation based on GWT's RequestBuilder and
* AngularJS's promise pattern. This implementation is provided for two reasons.
* <ol>
* <li>The current implementation based on $http does not work. (<a
* href="https://github.com/kyoken74/gwt-angular/issues/16">Issue #16</a>)</li>
* <li>To demonstrate a RequestBuilder reuse in AngularJS for the users working
* with pre-existing code.</li>
* </ol>
* There are a couple of different ways to reuse RequestBuilder in AngularJS.
* One way is to wire it to the AngularJS's promise pattern (Q) like in this
* implementation. Another way is to invoke AngularJS's <code>$scope.$digest()
* </code> to refresh the view once the data is retrieved from the remote
* server.
* <p>
* This code demonstrates the use of Q rather than <code>$scope</code> because
* the wrapper around <code>$scope</code> is not yet implemented in
* gwt-angular-core (<a
* href="https://github.com/kyoken74/gwt-angular/issues/6">Issue #6</a>), and
* also because using Q is a less kludgy way to solve this problem.
* </p>
* <p>
* If one must use <code>$scope.$digest</code> solution, he or she should be
* aware that the invocation should consider the possibility that the digest is
* already in progress at the time of receiving the asynchronous response. To
* account for this condition, the following code should be provided.
*
* <pre>
* if (!$scope.$$phase) {
* $scope.$digest()
* }
* </pre>
*
* </p>
*
* @author kyoken74
* @see Q
* @see Promise
*/
public class HttpClient implements Service {
@Injector.Inject
private Q q;
public Promise<Response> get(String url) {
return send(RequestBuilder.GET, url, null);
}
public Promise<Response> post(String url, String data) {
return send(RequestBuilder.POST, url, data);
}
public Promise<Response> put(String url, String data) {
return send(RequestBuilder.PUT, url, data);
}
public Promise<Response> delete(String url) {
return send(RequestBuilder.DELETE, url, null);
}
public Promise<Response> send(Method method, String url, String data) {
final Deferred<Response> deferred = q.defer();
try {
//TODO support cancellation of requests
//TODO https://github.com/kyoken74/gwt-angular/issues/69
RequestBuilder builder = new RequestBuilder(method, url);
RequestCallback callback = new DeferredRequestCallback(deferred);
Request request = builder.sendRequest(data, callback);
deferred.progress(new HttpClientProgress(method.toString() + " " + url, request));
} catch (RequestException e) {
deferred.reject(e);
} catch (RuntimeException e) {
deferred.reject(e);
}
return deferred.promise();
}
}
class DeferredRequestCallback implements RequestCallback {
private final Deferred<Response> deferred;
public DeferredRequestCallback(Deferred<Response> deferred) {
this.deferred = deferred;
}
@Override
public void onResponseReceived(Request request, Response response) {
deferred.resolve(response);
}
@Override
public void onError(Request request, Throwable exception) {
deferred.reject(exception);
}
}