com.google.api.explorer.client.history.EmbeddedHistoryItemView.java Source code

Java tutorial

Introduction

Here is the source code for com.google.api.explorer.client.history.EmbeddedHistoryItemView.java

Source

/*
 * Copyright (C) 2010 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.history;

import com.google.api.explorer.client.base.ApiMethod.HttpMethod;
import com.google.api.explorer.client.base.ApiRequest;
import com.google.api.explorer.client.base.ApiResponse;
import com.google.api.explorer.client.base.ApiResponse.HeaderValue;
import com.google.api.explorer.client.base.Config;
import com.google.api.explorer.client.base.ExplorerConfig;
import com.google.api.explorer.client.base.dynamicjso.DynamicJso;
import com.google.api.explorer.client.history.JsonPrettifier.JsonFormatException;
import com.google.api.explorer.client.history.JsonPrettifier.PrettifierLinkFactory;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsonUtils;
import com.google.gwt.dom.client.PreElement;
import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;

import java.util.Date;
import java.util.Map;
import java.util.SortedMap;

public class EmbeddedHistoryItemView extends Composite {

    private static HistoryItemUiBinder uiBinder = GWT.create(HistoryItemUiBinder.class);

    private static final String IMAGE_TYPE_PREFIX = "image/";
    private static final String TEXT_TYPE_PREFIX = "text/";
    private static final String CONTENT_TYPE_HEADER = "content-type";
    private static final String AUTH_HEADER = "authorization";

    interface HistoryItemUiBinder extends UiBinder<Widget, EmbeddedHistoryItemView> {
    }

    interface EmbeddedHistoryItemViewStyle extends CssResource {
        String fadeIn();
    }

    @UiField
    public Panel titleBar;
    @UiField
    public SpanElement title;
    @UiField
    public SpanElement time;
    @UiField
    public SimplePanel errorPanel;
    @UiField
    public PreElement requestDiv;
    @UiField
    public FlowPanel requestBodyDiv;
    @UiField
    public PreElement statusDiv;
    @UiField
    public Label showHideHeaders;
    @UiField
    public PreElement responseHeadersDiv;
    @UiField
    public FlowPanel responseBodyDiv;
    @UiField
    public Panel executing;
    @UiField
    public HTMLPanel wireContent;

    @UiField
    EmbeddedHistoryItemViewStyle style;

    private final ApiRequest request;
    private final String realPathFragment;

    public EmbeddedHistoryItemView(ApiRequest request) {
        initWidget();

        this.request = request;

        // Stash the real URL in case we need it for loading media
        realPathFragment = request.getRequestPath();

        // Replace the API key with a fake version if the default was used
        if (ExplorerConfig.API_KEY.equals(request.getApiKey())) {
            request.setApiKey("{YOUR_API_KEY}");
        }

        String prefix = request.getMethod().getId() + " executed ";
        PrettyDate.keepMakingPretty(new Date(), prefix, title);

        String dateString = DateTimeFormat.getFormat(PredefinedFormat.DATE_TIME_SHORT).format(new Date());
        title.setTitle(dateString);

        requestDiv.setInnerText(getRequestString(request));
    }

    /**
     * Complete the partially filled history item with the response data.
     *
     * @param response Response data.
     * @param timeMillis Time that execution took in milliseconds.
     * @param linkFactory Link factory that is used to generate hyperlink and menu links in the
     *        response view.
     */
    public void complete(ApiResponse response, long timeMillis, PrettifierLinkFactory linkFactory) {
        executing.setVisible(false);
        wireContent.addStyleName(style.fadeIn());
        time.setInnerText("time to execute: " + timeMillis + " ms");
        statusDiv.setInnerText(response.getStatus() + " " + response.getStatusText());

        // Headers are hidden by default.
        UIObject.setVisible(responseHeadersDiv, false);
        responseHeadersDiv.setInnerText(getResponseHeadersString(response));
        try {
            JsonPrettifier.prettify(request.getService(), requestBodyDiv, request.getRequestBody(), linkFactory);
        } catch (JsonFormatException e) {
            // We should only be generating valid requests
            requestBodyDiv.add(new InlineLabel(request.getRequestBody()));
        }

        setResponseContent(request, response, realPathFragment, linkFactory);
    }

    /**
     * Set the value of the panel reserved for the formatted response. There are a couple different
     * scenarios to tackle. If we can determine that the request returned an image, and the request is
     * repeatable, we will create an image tag with a source of the original request.
     *
     * If the response is a non-JSON text type, we just show it directly.
     *
     * In all other cases we try to process the text as JSON and if for some reason that fails, we
     * just hide it under an opaque tag that says as much information as we know about the response.
     *
     * @param request Request object with the API key replaced.
     * @param response Response from the server.
     * @param originalPath Path object before we replaced the API key.
     * @param linkFactory Which links factory should be used when generating links and navigation
     *        menus.
     */
    private void setResponseContent(ApiRequest request, ApiResponse response, String originalPath,
            PrettifierLinkFactory linkFactory) {

        HeaderValue authorization = response.getHeaders().get(AUTH_HEADER);
        HeaderValue contentTypeHeader = response.getHeaders().get(CONTENT_TYPE_HEADER);
        GWT.log("Headers: " + response.getHeaders().entrySet());
        String contentType = contentTypeHeader == null ? "Unspecified" : contentTypeHeader.getValue();

        if (request.getHttpMethod() == HttpMethod.GET && contentType.startsWith(IMAGE_TYPE_PREFIX)
                && authorization == null) {

            // In the very special case that we performed a get and were given an
            // image, display it
            Image img = new Image();
            img.setUrl(Config.getBaseUrl() + originalPath);
            img.setAltText(Config.getBaseUrl() + request.getRequestPath());
            responseBodyDiv.add(img);
        } else if (contentType.startsWith(TEXT_TYPE_PREFIX)) {
            // We have non-JSON text, just show it.
            responseBodyDiv.add(new Label(response.getBodyAsString()));
        } else {
            // Treat the response as JSON, although we don't really know what it is
            try {
                JsonPrettifier.prettify(request.getService(), responseBodyDiv, response.getBodyAsString(),
                        linkFactory);
            } catch (JsonFormatException e) {
                // If JSON processing fails, just say what we know about the data
                responseBodyDiv.add(new Label("[" + contentType + " data]"));
            }

            // Check if there was an error, and, if so, display it to the user.
            ErrorCase error = getErrorMessage(response);
            if (error != null) {
                setErrorMessage(error.getErrorLabel());
            }
        }
    }

    protected void initWidget() {
        initWidget(uiBinder.createAndBindUi(this));
    }

    @UiHandler("showHideHeaders")
    public void showHide(ClickEvent event) {
        showHideHeaders.setText(UIObject.isVisible(responseHeadersDiv) ? "- Show headers -" : "- Hide headers -");
        UIObject.setVisible(responseHeadersDiv, !UIObject.isVisible(responseHeadersDiv));
    }

    private static String getRequestString(ApiRequest request) {
        StringBuilder sb = new StringBuilder().append(request.getHttpMethod().name()).append(' ')
                .append(Config.getBaseUrl())
                // If the standard API key is being used, mask it in the UI.
                // The URL is already URL-escaped before making the request, so we don't
                // want to double-escape it.
                .append(request.getRequestPath());

        // Display headers that were set on the request.
        // TODO(jasonhall): This can be prettier.
        sb.append('\n');
        for (Map.Entry<String, String> entry : request.getHeaders().entrySet()) {
            sb.append('\n').append(entry.getKey()).append(":  ").append(entry.getValue());
        }

        return sb.toString();
    }

    private static ErrorCase getErrorMessage(ApiResponse response) {
        // This requires a try-catch because there is no way to proactively check
        // that the JSON is both present and valid without just trying to parse it.
        try {
            DynamicJso jso = JsonUtils.safeEval(response.getBodyAsString());
            if (jso.get("error") != null) {
                return ErrorCase.forJsonString(response.getBodyAsString());
            }
        } catch (IllegalArgumentException e) {
            // Not valid json, definitely not an error payload.
        }
        return null;
    }

    private static String getResponseHeadersString(ApiResponse response) {
        StringBuilder sb = new StringBuilder();

        SortedMap<String, HeaderValue> sorted = Maps.newTreeMap(Ordering.natural());
        sorted.putAll(response.getHeaders());

        for (HeaderValue header : sorted.values()) {
            sb.append(header.getKey()).append(":  ").append(header.getValue()).append('\n');
        }

        return sb.toString();
    }

    private void setErrorMessage(Widget prettyMessage) {
        errorPanel.setVisible(true);
        errorPanel.add(prettyMessage);
    }
}