/* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.google.api.explorer.client.base.http.crossdomain; import com.google.api.explorer.client.base.ApiRequest; import com.google.api.explorer.client.base.ApiResponse; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import com.google.gwt.core.client.Callback; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.ScriptInjector; import com.google.gwt.user.client.rpc.AsyncCallback; import java.util.List; /** * Builds requests to make to an cross-domain proxy iframe. * * <p> * This consists of adding a <script> tag to the page to load the JS library to * make cross-domain requests to the server. * </p> * * @author jasonhall@google.com (Jason Hall) */ public class CrossDomainRequestBuilder { private static final String JS_CLIENT_URL = "https://apis.google.com/js/client.js?onload=__apis_explorer_load_callback"; private int timeoutMillis; private List<OutstandingRequest> outstandingRequests = Lists.newArrayList(); private static native boolean isScriptLoaded() /*-{ return !!$wnd.googleapis && !!$wnd.googleapis.newHttpRequest; }-*/; @VisibleForTesting protected static native void addLoadCallback(CrossDomainRequestBuilder builder) /*-{ $wnd.__apis_explorer_load_callback = function() { builder. @com.google.api.explorer.client.base.http.crossdomain.CrossDomainRequestBuilder::scriptFinishedLoading()(); }; }-*/; public void scriptFinishedLoading() { setBaseUrl(); for (OutstandingRequest request : outstandingRequests) { doMakeRequest(request.request, request.xdr); } } public void setTimeoutMillis(int timeoutMillis) { this.timeoutMillis = timeoutMillis; } public CrossDomainRequest makeRequest( final ApiRequest request, AsyncCallback<ApiResponse> callback) { final CrossDomainRequest xdr = new CrossDomainRequest(callback, timeoutMillis); /** Adds a script tag to the page to load the JS library used to make requests. */ if (!isScriptLoaded()) { outstandingRequests.add(new OutstandingRequest(request, xdr)); // If we are the only request waiting, it is our responsibility to load the library. if (outstandingRequests.size() == 1) { addLoadCallback(this); ScriptInjector.fromUrl(JS_CLIENT_URL) .setWindow(ScriptInjector.TOP_WINDOW) .setCallback(new Callback<Void, Exception>() { @Override public void onFailure(Exception e) { throw new RuntimeException(e); } @Override public void onSuccess(Void arg0) { // Intentionally blank, callback will be invoked automatically } }).inject(); } } else { doMakeRequest(request, xdr); } return xdr; } private <T> void doMakeRequest(ApiRequest request, final CrossDomainRequest xdr) { JavaScriptObject jso = CrossDomainRequest.convertRequest(request); xdr.sendRequest(jso); } private static native void setBaseUrl() /*-{ var proxy = @com.google.api.explorer.client.base.Config::baseUrl + '/static/proxy.html'; $wnd.gapi.config.update('googleapis.config/proxy', proxy); }-*/; private static class OutstandingRequest { public final ApiRequest request; public final CrossDomainRequest xdr; public OutstandingRequest(ApiRequest request, CrossDomainRequest xdr) { this.request = request; this.xdr = xdr; } } }