/*
* 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.embedded;
import com.google.api.explorer.client.AnalyticsRequestFinishedCallback;
import com.google.api.explorer.client.AuthManager;
import com.google.api.explorer.client.Resources;
import com.google.api.explorer.client.analytics.AnalyticsManager;
import com.google.api.explorer.client.analytics.AnalyticsManager.AnalyticsEvent;
import com.google.api.explorer.client.analytics.AnalyticsManagerImpl;
import com.google.api.explorer.client.base.ApiRequest;
import com.google.api.explorer.client.base.ApiResponse;
import com.google.api.explorer.client.base.ApiService;
import com.google.api.explorer.client.base.ApiServiceFactory;
import com.google.api.explorer.client.base.Config;
import com.google.api.explorer.client.base.ExplorerConfig;
import com.google.api.explorer.client.base.ServiceLoader;
import com.google.api.explorer.client.history.EmbeddedHistoryItemView;
import com.google.api.explorer.client.history.JsonPrettifier;
import com.google.api.explorer.client.routing.URLFragment;
import com.google.api.gwt.oauth2.client.Auth;
import com.google.common.collect.Multimap;
import com.google.gwt.core.client.Callback;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.RootPanel;
/**
* Entry Point for Embedded Explorer module.
*
* <p>
* <b>Usage</b>: This assumes that the hosting page includes a <div> element
* with data attributes specifying the service, version, and method to load (in
* "data-service", "data-version" and "data-method" attributes, respectively).
* If these are not given, an {@link IllegalStateException} is thrown.
* </p>
*
* <p>
* Additional method parameters can be specified with the "data-params"
* attribute on the div, declaring the params in the form
* "key1=val1&key2=val2&..."
* </p>
*
* @author jasonhall@google.com (Jason Hall)
*/
public class EmbeddedEntryPoint implements EntryPoint {
private static final String EMBEDDING_ID = "embedded-explorer";
private static final String SERVICE_ATTR = "data-service";
private static final String VERSION_ATTR = "data-version";
private static final String METHOD_ATTR = "data-method";
private static final String PARAMS_ATTR = "data-params";
private static final String BASE_ATTR = "data-baseUrl";
private static final String AUTH_POPUP_ATTR = "data-auth-popup";
private static final boolean SHOW_AUTH = true;
private RootPanel root;
private ServiceLoader serviceLoader;
private AuthManager authManager;
private AnalyticsManager analytics;
@Override
public void onModuleLoad() {
// Make sure that CSS gets injected.
Resources.INSTANCE.style().ensureInjected();
EmbeddedResources.INSTANCE.style().ensureInjected();
root = RootPanel.get(EMBEDDING_ID);
// Try to get the root div, and service/version/method to load. If any are
// not present, throw an error and give up.
if (root == null) {
throw new IllegalStateException("Could not find a suitable drop-in div.");
}
final Element rootElement = root.getElement();
String serviceName = rootElement.getAttribute(SERVICE_ATTR);
String versionName = rootElement.getAttribute(VERSION_ATTR);
String methodName = rootElement.getAttribute(METHOD_ATTR);
String token = rootElement.getAttribute(PARAMS_ATTR);
final Multimap<String, String> params = URLFragment.parseParams(token);
if (serviceName.isEmpty() || versionName.isEmpty() || methodName.isEmpty()) {
throw new IllegalStateException("Could not determine service, version and method to load.");
}
// Set the OAuth2 popup window URL if one is given in the embedding div.
String authPopup = rootElement.getAttribute(AUTH_POPUP_ATTR);
if (!authPopup.isEmpty()) {
Auth.get().setOAuthWindowUrl(authPopup);
}
// Set the base URL if one is given in the embedding div.
String base = rootElement.getAttribute(BASE_ATTR);
if (base != null && !base.isEmpty()) {
Config.setBaseUrl(base);
}
// Set up static resources.
JsonPrettifier.setResources(Resources.INSTANCE);
// Set the API key and application name to use for calls from the Explorer.
Config.setApiKey(ExplorerConfig.API_KEY);
// Dependencies for the UI
authManager = new AuthManager();
serviceLoader = new ServiceLoader(ApiServiceFactory.INSTANCE);
analytics = new AnalyticsManagerImpl();
analytics.trackEventWithValue(AnalyticsEvent.LOAD_EXPLORER, "Embedded");
loadServiceMethod(serviceName, versionName, methodName, params);
exportUpdate(this);
}
private void loadServiceMethod(String serviceName, String versionName, final String methodName,
final Multimap<String, String> params) {
serviceLoader.loadService(serviceName, versionName, new Callback<ApiService, String>() {
@Override
public void onSuccess(ApiService service) {
ShowHistoryCallback callback = new ShowHistoryCallback(analytics);
EmbeddedView view = new EmbeddedView(authManager,
service,
service.resolveMethod(methodName),
params,
callback,
SHOW_AUTH,
analytics);
callback.localView = view;
// Construct the UI and add it to the page.
root.clear();
root.add(view);
}
@Override
public void onFailure(String reason) {
analytics.trackEvent(AnalyticsEvent.LOAD_DISCOVERY_FAILURE);
}
});
}
private static class ShowHistoryCallback extends AnalyticsRequestFinishedCallback {
public EmbeddedView localView;
private ShowHistoryCallback(AnalyticsManager analytics) {
super(analytics);
}
@Override
public void finished(ApiRequest request, ApiResponse response, long startTime, long endTime) {
super.finished(request, response, startTime, endTime);
EmbeddedHistoryItemView historyItem = new EmbeddedHistoryItemView(request);
historyItem.complete(response, endTime - startTime, JsonPrettifier.EXTERNAL_LINK_FACTORY);
localView.showHistoryItem(historyItem);
}
}
/**
* Exports a globally-scoped JS function named 'updateExplorer' that the
* outer page can call to update the embedded UI.
*/
private final native void exportUpdate(EmbeddedEntryPoint that) /*-{
$wnd.updateExplorer = $entry(function(service, version, method, token) {
that.
@com.google.api.explorer.client.embedded.EmbeddedEntryPoint::update(*)
(service, version, method, token || "");
});
}-*/;
@SuppressWarnings("unused") // Used in JSNI
private void update(String serviceName, String version, String methodName, String token) {
loadServiceMethod(serviceName, version, methodName, URLFragment.parseParams(token));
}
}