/** * Copyright 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 org.waveprotocol.wave.client.gadget.renderer; import com.google.gwt.json.client.JSONBoolean; import com.google.gwt.json.client.JSONNumber; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONString; import com.google.gwt.json.client.JSONValue; import org.waveprotocol.wave.client.gadget.StateMap; import org.waveprotocol.wave.model.util.CollectionUtils; import org.waveprotocol.wave.model.util.ReadableStringSet; import org.waveprotocol.wave.model.util.StringMap; /** * Gadget metadata container and parser class. * * TODO(user): Replace gwt JSON classes with either overlay types or other * lightweight alternative. * * TODO(davidbyttow): Reduce this class to just metadata and pull some of the * data into a single GadgetData class used by Gadget widgets. * * TODO(davidbyttow): Unit tests. * * TODO(davidbyttow): Factor out the parsing code, possibly use GWT javascript * objects instead. * */ public class GadgetMetadata { /** Gadget View info. */ /** Metadata fields. */ private String iframeUrl; private String url; private String moduleId; private String title; private String titleUrl; private String directoryTitle; private String thumbnail; private String screenshot; private String author; private String authorEmail; private Long height; private Long width; private Boolean scrolling; /** Gadget View info. */ private final StringMap<View> views = CollectionUtils.createStringMap(); /** * Encapsulates gadget view information. */ private static class View { private String type; private Long preferredHeight; private Long preferredWidth; } /** User Prefs object. */ private final GadgetUserPrefs userPrefs = GadgetUserPrefs.create(); /** * Constructs the object from metadata JSON. * * @param metadataJson JSON object to extract the data from. */ public GadgetMetadata(JSONObject metadataJson) { parse(metadataJson); } /** * Helper function to extract a string value from given JSON object. * * @param json JSON object to extract the value from. * @param key key of the value to extract. * @return the string object extracted from JSON (can be null if the value * does not exist or is invalid. */ private static String getJsonStringValue(JSONObject json, String key) { JSONValue value = json.get(key); JSONString string = (value == null) ? null : value.isString(); if (string != null) { return string.stringValue(); } else { return null; } } /** * Helper function to extract a long value from given JSON object. * * @param json JSON object to extract the value from. * @param key key of the value to extract. * @return the Long object extracted from JSON (can be null if the value does * not exist or is invalid. */ private static Long getJsonLongValue(JSONObject json, String key) { JSONValue value = json.get(key); JSONNumber number = (value == null) ? null : value.isNumber(); if (number != null) { return Math.round(number.doubleValue()); } else { return null; } } /** * Helper function to extract a boolean value from given JSON object. * * @param json JSON object to extract the value from. * @param key key of the value to extract. * @return the Boolean object extracted from JSON (can be null if the value * does not exist or is invalid. */ private static Boolean getJsonBooleanValue(JSONObject json, String key) { JSONValue value = json.get(key); JSONBoolean bool = (value == null) ? null : value.isBoolean(); if (bool != null) { return bool.booleanValue(); } else { return null; } } /** * Helper function to extract a JSONObject from a JSONValue if it exists. * * @param json JSON object to extract the value from. * @param key key of the value to extract. * @return the JSONObject if it exists. */ private static JSONObject getJsonObjectValue(JSONObject json, String key) { JSONValue value = json.get(key); return (value != null) ? value.isObject() : null; } /** * Parses JSON object to extract metadata information. * * @param gadget JSON object returned in the gadget field from the server. */ public void parse(JSONObject gadget) { iframeUrl = getJsonStringValue(gadget, "iframeUrl"); // Get rid of the protocol as we should rely on the browser to do the right // thing with "//" as the beginning of the url. // By doing this it also works around an issue in shindig where it shouldn't // put "//" in front of "http://" see: // https://issues.apache.org/jira/browse/SHINDIG-1460?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12928110#action_12928110 // This work around may no longer be needed on the next version of shindig // Added null check on iframeUrl.Issue #166:Client shiny on broken gadget. if(iframeUrl != null) { iframeUrl = iframeUrl.replaceFirst("^//http[s]?://", "//"); } url = getJsonStringValue(gadget, "url"); moduleId = getJsonStringValue(gadget, "moduleId"); title = getJsonStringValue(gadget, "title"); titleUrl = getJsonStringValue(gadget, "titleUrl"); directoryTitle = getJsonStringValue(gadget, "directoryTitle"); thumbnail = getJsonStringValue(gadget, "thumbnail"); screenshot = getJsonStringValue(gadget, "screenshot"); author = getJsonStringValue(gadget, "author"); authorEmail = getJsonStringValue(gadget, "authorEmail"); height = getJsonLongValue(gadget, "height"); width = getJsonLongValue(gadget, "width"); scrolling = getJsonBooleanValue(gadget, "scrolling"); // Added null check on gadget.get("userPrefs").Issue #166:Client shiny on broken gadget. if(gadget.get("userPrefs") != null) { userPrefs.parseDefaultValues(gadget.get("userPrefs").isObject()); } JSONObject gadgetViews = getJsonObjectValue(gadget, "views"); if (gadgetViews != null) { View lastView = null; for (String viewName : gadgetViews.keySet()) { JSONObject viewJson = gadgetViews.get(viewName).isObject(); View v = new View(); v.type = viewName; v.preferredHeight = getJsonLongValue(viewJson, "preferredHeight"); v.preferredWidth = getJsonLongValue(viewJson, "preferredWidth"); views.put(v.type, v); lastView = v; } } } /** Metadata field accessors. */ public boolean hasView(String view) { return views.containsKey(view); } public String getIframeUrl(String view) { return iframeUrl; } public boolean hasPreferredWidth(String view) { View v = views.get(view); return v != null && v.preferredWidth != null; } public long getPreferredWidth(String view) { View v = views.get(view); if (v == null) { return 0; } return v.preferredWidth; } public boolean hasPreferredHeight(String view) { View v = views.get(view); return v != null && v.preferredHeight != null; } public long getPreferredHeight(String view) { View v = views.get(view); if (v == null) { return 0; } return v.preferredHeight; } public boolean hasIframeUrl() { return iframeUrl != null; } public String getIframeUrl() { return iframeUrl; } public boolean hasUrl() { return url != null; } public String getUrl() { return url; } public boolean hasModuleId() { return moduleId != null; } public String getModuleId() { return moduleId; } public boolean hasTitle() { return title != null; } public String getTitle() { return title; } public boolean hasTitleUrl() { return titleUrl != null; } public String getTitleUrl() { return titleUrl; } public boolean hasHeight() { return height != null; } public long getHeight() { return height; } public boolean hasWidth() { return width != null; } public long getWidth() { return width; } public boolean hasScrolling() { return scrolling != null; } public Boolean getScrolling() { return scrolling; } public boolean hasDirectoryTitle() { return directoryTitle != null; } public String getDirectoryTitle() { return directoryTitle; } public boolean hasThumbnail() { return thumbnail != null; } public String getThumbnail() { return thumbnail; } public boolean hasAuthor() { return author != null; } public String getAuthor() { return author; } public boolean hasAuthorEmail() { return authorEmail != null; } public String getAuthorEmail() { return authorEmail; } public boolean hasScreenshot() { return screenshot != null; } public String getScreenshot() { return screenshot; } public StateMap getUserPrefs() { return userPrefs; } /** * @returns Set of views implemented by the gadget. */ public ReadableStringSet getViewSet() { return views.keySet(); } }