All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.shindig.gadgets.spec.ModulePrefs Maven / Gradle / Ivy

Go to download

Renders gadgets, provides the gadget metadata service, and serves all javascript required by the OpenSocial specification.

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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.apache.shindig.gadgets.spec;

import com.google.common.base.Joiner;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;

import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.shindig.common.uri.Uri;
import org.apache.shindig.gadgets.variables.Substitutions;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;




/**
 * Represents the ModulePrefs element of a gadget spec.
 *
 * This encapsulates most gadget meta data, including everything except for
 * Content and UserPref nodes.
 */
public class ModulePrefs {
	

  private static final String ATTR_TITLE = "title";
  private static final String ATTR_TITLE_URL = "title_url";
  private static final String ATTR_DESCRIPTION = "description";
  private static final String ATTR_AUTHOR = "author";
  private static final String ATTR_AUTHOR_EMAIL = "author_email";
  private static final String ATTR_SCREENSHOT = "screenshot";
  private static final String ATTR_THUMBNAIL = "thumbnail";
  private static final String ATTR_DIRECTORY_TITLE = "directory_title";
  private static final String ATTR_AUTHOR_AFFILIATION = "author_affiliation";
  private static final String ATTR_AUTHOR_LOCATION = "author_location";
  private static final String ATTR_AUTHOR_PHOTO = "author_photo";
  private static final String ATTR_AUTHOR_ABOUTME = "author_aboutme";
  private static final String ATTR_AUTHOR_QUOTE = "author_quote";
  private static final String ATTR_AUTHOR_LINK = "author_link";
  private static final String ATTR_SHOW_STATS = "show_stats";
  private static final String ATTR_SHOW_IN_DIRECTORY = "show_in_directory";
  private static final String ATTR_SINGLETON = "singleton";
  private static final String ATTR_SCALING = "scaling";
  private static final String ATTR_SCROLLING = "scrolling";
  private static final String ATTR_DOCTYPE = "doctype";
  private static final String ATTR_WIDTH = "width";
  private static final String ATTR_HEIGHT = "height";
  private static final String ATTR_CATEGORY = "category";
  private static final String ATTR_CATEGORY2 = "category2";
  private static final Uri EMPTY_URI = Uri.parse("");
  private static final String UP_SUBST_PREFIX = "__UP_";
  
  // Used to identify Locales that are globally scoped
  private static final String GLOBAL_LOCALE = "";

  private final Map attributes;
  private final Uri base;
  private final boolean needsUserPrefSubstitution;

  public ModulePrefs(Element element, Uri base) throws SpecParserException {
    this.base = base;
    attributes = Maps.newHashMap();
    NamedNodeMap attributeNodes = element.getAttributes();
    for (int i = 0; i < attributeNodes.getLength(); i++) {
      Node node = attributeNodes.item(i);
      attributes.put(node.getNodeName(), node.getNodeValue());
    }

    categories = ImmutableList.of(getAttribute(ATTR_CATEGORY, ""), getAttribute(ATTR_CATEGORY2, ""));

    // Eventually use a list of classes
    MutableBoolean oauthMarker = new MutableBoolean(false);
    
    Set visitors = ImmutableSet.of(
        new FeatureVisitor(oauthMarker),
        new PreloadVisitor(),
        new OAuthVisitor(oauthMarker),
        new OAuth2Visitor(oauthMarker),
        new IconVisitor(),
        new LocaleVisitor(),
        new LinkVisitor(),
        new ExtraElementsVisitor() // keep this last since it accepts any tag
    );

    walk(element, visitors);

    // Tell the visitors to apply their knowledge
    for (ElementVisitor ev : visitors) {
      ev.apply(this);
    }

    needsUserPrefSubstitution = prefsNeedsUserPrefSubstitution(this);
  }

  /**
   * Produces a new, substituted ModulePrefs
   * @param prefs An existing ModulePrefs instance
   * @param substituter The substituter to apply
   */
  private ModulePrefs(ModulePrefs prefs, Substitutions substituter) {
    base = prefs.base;
    categories = prefs.getCategories();
    features = prefs.getFeatures();
    globalFeatures = prefs.globalFeatures;
    allFeatures = prefs.getAllFeatures();
    allLocales = prefs.allLocales;
    locales = prefs.locales;
    oauth = prefs.oauth;
    oauth2 = prefs.oauth2;

    List preloads = Lists.newArrayList();
    for (Preload preload : prefs.preloads) {
      preloads.add(preload.substitute(substituter));
    }
    this.preloads = ImmutableList.copyOf(preloads);

    List icons = Lists.newArrayList();
    for (Icon icon : prefs.icons) {
      icons.add(icon.substitute(substituter));
    }
    this.icons = ImmutableList.copyOf(icons);

    ImmutableMap.Builder links = ImmutableMap.builder();
    for (LinkSpec link : prefs.links.values()) {
      LinkSpec sub = link.substitute(substituter);
      links.put(sub.getRel(), sub);
    }
    this.links = links.build();

    ImmutableMap.Builder attributes = ImmutableMap.builder();
    for (Map.Entry attr : prefs.attributes.entrySet()) {
      String substituted = substituter.substituteString(attr.getValue());
      attributes.put(attr.getKey(), substituted);
    }
    
    ImmutableMap.Builder featureBuilder= ImmutableMap.builder();
    for (Map.Entry feature : features.entrySet()) {
      ImmutableMultimap.Builder params = ImmutableMultimap.builder();
      for (Map.Entry param: feature.getValue().getParams().entries()){     
        String substituted=substituter.substituteString(param.getValue());
        params.put(param.getKey(), substituted);
      }
      Feature oldFeature=feature.getValue();
      Feature newFeature=new Feature(oldFeature.getName(), params.build(), oldFeature.getRequired(), oldFeature.getViews());
      featureBuilder.put(feature.getKey(), newFeature);
    }
    this.features=featureBuilder.build();
    
    
    this.extraElements = ImmutableMultimap.copyOf(prefs.extraElements);
    this.attributes = attributes.build();
    this.needsUserPrefSubstitution = prefs.needsUserPrefSubstitution;
  }

  // Canonical spec items first.

  /**
   * ModulePrefs@title
   *
   * User Pref + Message Bundle + Bidi
   */
  public String getTitle() {
    String title = getAttribute(ATTR_TITLE);
    return title == null ? "" : title;
  }

  /**
   * ModulePrefs@title_url
   *
   * User Pref + Message Bundle + Bidi
   */
  public Uri getTitleUrl() {
    return getUriAttribute(ATTR_TITLE_URL);
  }

  /**
   * ModulePrefs@description
   *
   * Message Bundles
   */
  public String getDescription() {
    return getAttribute(ATTR_DESCRIPTION);
  }

  /**
   * ModulePrefs@author
   *
   * Message Bundles
   */
  public String getAuthor() {
    return getAttribute(ATTR_AUTHOR);
  }

  /**
   * ModulePrefs@author_email
   *
   * Message Bundles
   */
  public String getAuthorEmail() {
    return getAttribute(ATTR_AUTHOR_EMAIL);
  }

  /**
   * ModulePrefs@screenshot
   *
   * Message Bundles
   */
  public Uri getScreenshot() {
    return getUriAttribute(ATTR_SCREENSHOT);
  }

  /**
   * ModulePrefs@thumbnail
   *
   * Message Bundles
   */
  public Uri getThumbnail() {
    return getUriAttribute(ATTR_THUMBNAIL);
  }

  // Extended data (typically used by directories)

  /**
   * ModulePrefs@directory_title
   *
   * Message Bundles
   */
  public String getDirectoryTitle() {
    return getAttribute(ATTR_DIRECTORY_TITLE);
  }

  /**
   * ModulePrefs@author_affiliation
   *
   * Message Bundles
   */
  public String getAuthorAffiliation() {
    return getAttribute(ATTR_AUTHOR_AFFILIATION);
  }

  /**
   * ModulePrefs@author_location
   *
   * Message Bundles
   */
  public String getAuthorLocation() {
    return getAttribute(ATTR_AUTHOR_LOCATION);
  }

  /**
   * ModulePrefs@author_photo
   *
   * Message Bundles
   */
  public Uri getAuthorPhoto() {
    return getUriAttribute(ATTR_AUTHOR_PHOTO);
  }

  /**
   * ModulePrefs@author_aboutme
   *
   * Message Bundles
   */
  public String getAuthorAboutme() {
    return getAttribute(ATTR_AUTHOR_ABOUTME);
  }

  /**
   * ModulePrefs@author_quote
   *
   * Message Bundles
   */
  public String getAuthorQuote() {
    return getAttribute(ATTR_AUTHOR_QUOTE);
  }

  /**
   * ModulePrefs@author_link
   *
   * Message Bundles
   */
  public Uri getAuthorLink() {
    return getUriAttribute(ATTR_AUTHOR_LINK);
  }

  /**
   * ModulePrefs@show_stats
   */
  public boolean getShowStats() {
    return getBoolAttribute(ATTR_SHOW_STATS);
  }

  /**
   * ModulePrefs@show_in_directory
   */
  public boolean getShowInDirectory() {
    return getBoolAttribute(ATTR_SHOW_IN_DIRECTORY);
  }

  /**
   * ModulePrefs@singleton
   */
  public boolean getSingleton() {
    return getBoolAttribute(ATTR_SINGLETON);
  }

  /**
   * ModulePrefs@scaling
   */
  public boolean getScaling() {
    return getBoolAttribute(ATTR_SCALING);
  }

  /**
   * ModulePrefs@scrolling
   */
  public boolean getScrolling() {
    return getBoolAttribute(ATTR_SCROLLING);
  }

  /**
   * ModuleSpec@width
   */
  public int getWidth() {
    return getIntAttribute(ATTR_WIDTH);
  }

  /**
   * ModuleSpec@height
   */
  public int getHeight() {
    return getIntAttribute(ATTR_HEIGHT);
  }
  
  /**
   * Returns this Gadget's doctype mode.  If null, we will use default mode.
   * 
   * @return Value of doctype attribute
   */
  public String getDoctype(){
    return getAttribute(ATTR_DOCTYPE);
  }

  /**
   * @param name the attribute name
   * @return the value of an ModulePrefs attribute by name, or null if the
   *     attribute doesn't exist
   */
  public String getAttribute(String name) {
    return attributes.get(name);
  }

  /**
   * @param name the attribute name
   * @param defaultValue the default Value
   * @return the value of an ModulePrefs attribute by name, or the default
   *     value if the attribute doesn't exist
   */
  public String getAttribute(String name, String defaultValue) {
    String value = getAttribute(name);
    if (value == null) {
      return defaultValue;
    } else {
      return value;
    }
  }

  /**
   * @param name the attribute name
   * @return the attribute by name converted to an URI, or the empty URI if the
   *    attribute couldn't be converted
   */
  public Uri getUriAttribute(String name) {
    String uriAttribute = getAttribute(name);
    if (uriAttribute != null) {
      try {
        Uri uri = Uri.parse(uriAttribute);
        return base.resolve(uri);
      } catch (IllegalArgumentException e) {
        return EMPTY_URI;
      }
    }
    return EMPTY_URI;
  }

  /**
   * @param name the attribute name
   * @return the attribute by name converted to a boolean (false if the
   *     attribute doesn't exist)
   */
  public boolean getBoolAttribute(String name) {
    String value = getAttribute(name);
    return Boolean.parseBoolean(value);
  }

  /**
   * @param name the attribute name
   * @return the attribute by name converted to an integer, or 0 if the
   *     attribute doesn't exist or is not a valid number.
   */
  public int getIntAttribute(String name) {
    String value = getAttribute(name);
    if (value == null) {
      return 0;
    } else {
      try {
        return Integer.parseInt(value);
      } catch (NumberFormatException e) {
        return 0;
      }
    }
  }


  private final List categories;
  private List allFeatures;
  private Map features;
  private Map globalFeatures;
  private List preloads;
  private List icons;
  private Map>  locales;
  private Map allLocales;
  private Map links;
  private OAuthSpec oauth;
  private Multimap extraElements;
  private OAuth2Spec oauth2;


  /**
   * @return Returns a list of flattened attributes for:
   * ModuleSpec@category
   * ModuleSpec@category2
   */
  public List getCategories() {
    return categories;
  }
  
  /**
   * All features are included in ModulePrefs.  
   * View level features have view qualifiers appended.
   * @return a map of ModulePrefs/Require and ModulePrefs/Optional elements to Feature
   */
  public Map getFeatures() {
    return features;
  }
  
  
  /**
   * All features elements defined in ModulePrefs
   * @return a list of all Features included in ModulePrefs
   */
  public List getAllFeatures() {
    return allFeatures;
  }
  
  /**
   * Returns Map of features to load for the given View
   * @return a map of ModuleSpec/Require and ModuleSpec/Optional elements to Feature
   */
  public Map getViewFeatures(String view) {
    Map map = Maps.newHashMap();
    // Global features are in all views..
    map.putAll(globalFeatures);
    // By adding view level features last so they can override global feature configurations
    for (Feature feature : features.values()) {
      if (feature.getViews().contains(view)) {
        map.put(feature.getName(), feature);
      }
    }
    return map;
  }

  /**
   * @return a list of Preloads from the ModuleSpec/Preload element
   */
  public List getPreloads() {
    return preloads;
  }

  /**
   * @return a list of Icons from the ModuleSpec/Icon element
   */
  public List getIcons() {
    return icons;
  }

  /**
   * @return a Map of Locales to LocalSpec from the ModuleSpec/Locale element
   */
  public Map getLocales() {
    return allLocales;
  }

  /**
   * @return a map of Link names to LinkSpec from the ModuleSpec/Link element
   */
  public Map getLinks() {
    return links;
  }

  /**
   * @return an OAuthSpec built from the ModuleSpec/OAuthSpec element
   */
  public OAuthSpec getOAuthSpec() {
    return oauth;
  }
  
  /**
   * @return an OAuth2Spec built from the ModuleSpec/OAuthSpec element
   */
  public OAuth2Spec getOAuth2Spec() {
    return oauth2;
  }

  /**
   * @return a Multimap of tagnames to child elements of the ModuleSpec element
   */
  public Multimap getExtraElements() {
    return extraElements;
  }

  /**
   * Note: not part of the spec.
   *
   * @return true when UserPref-substitutable fields in this prefs require __UP_ substitution.
   */
  public boolean needsUserPrefSubstitution() {
    return needsUserPrefSubstitution;
  }

  /**
   * Gets the global locale spec for the given locale, if any exists.
   *
   * @return The locale spec, if there is a matching one, or null.
   */
  public LocaleSpec getGlobalLocale(Locale locale) {
    return getLocale(locale, GLOBAL_LOCALE);
  }
  
  /**
   * Gets the locale spec for the given locale and view, if any exists.
   *
   * @return The locale spec, if there is a matching one, or null.
   */
  public LocaleSpec getLocale(Locale locale, String view) {
    if (view == null) {
      view = GLOBAL_LOCALE;
    }
    Map viewLocales = locales.get(view);
    LocaleSpec locSpec = null;
    if (viewLocales != null) {
      locSpec = viewLocales.get(locale); // Check view specific locale...
    }
    if (locSpec == null && !view.equals(GLOBAL_LOCALE)) { // If not there, check Global map
      locSpec = getGlobalLocale(locale);
    }
    return locSpec;
  }

  /**
   * Produces a new ModulePrefs by substituting hangman variables from
   * substituter. See comments on individual fields to see what actually
   * has substitutions performed.
   *
   * @param substituter the substituter to execute
   * @return a substituted ModulePrefs
   */
  public ModulePrefs substitute(Substitutions substituter) {
    return new ModulePrefs(this, substituter);
  }


  /**
   * Walks child nodes of the given node.
   * @param element root node to be applied
   * @param visitors Set of visitors to apply to children of element.
   * @throws SpecParserException when encountering bad input
   */
  private static void walk(Element element, Set visitors)
      throws SpecParserException {
    NodeList children = element.getChildNodes();
    for (int i = 0, j = children.getLength(); i < j; ++i) {
      Node child = children.item(i);
      String tagName = child.getNodeName();

      if (!(child instanceof Element)) continue;

      // Try our visitors in order until we find a match
      for (ElementVisitor ev : visitors) {
        if (ev.visit(tagName, (Element)child))
          break;
      }
    }
  }

  @Override
  public String toString() {
    StringBuilder buf = new StringBuilder();
    buf.append(" attr : attributes.entrySet()) {
      buf.append(' ').append(attr.getKey()).append("=\"")
         .append(attr.getValue()).append('\"');
    }
    buf.append(">\n");

    Joiner j = Joiner.on("\n");

    j.appendTo(buf, preloads);
    j.appendTo(buf, features.values());
    j.appendTo(buf, icons);
    j.appendTo(buf, locales.values());
    j.appendTo(buf, links.values());

    if (oauth != null) {
      buf.append(oauth).append('\n');
    }
    
    if (extraElements != null) {
      for (Node node : extraElements.values()) {
        Source source = new DOMSource(node);
        StringWriter sw = new StringWriter();
        Result result = new StreamResult(sw);
        try {
          Transformer xformer = TransformerFactory.newInstance().newTransformer();
          xformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
          xformer.transform(source, result);
        } catch (TransformerConfigurationException e) {
          // ignore
        } catch (TransformerException e) {
          // ignore
        }
        buf.append(sw.toString());
      }
    }
    buf.append("");
    return buf.toString();
  }

  /**
   * @param prefs ModulePrefs object
   * @return true if any UserPref-substitutable fields in the given
   * {@code prefs} require such substitution.
   */
  static boolean prefsNeedsUserPrefSubstitution(ModulePrefs prefs) {
    for (Preload preload : prefs.preloads) {
      if (preload.getHref().toString().contains(UP_SUBST_PREFIX)) {
        return true;
      }
    }
    return prefs.getTitle().contains(UP_SUBST_PREFIX) ||
           prefs.getTitleUrl().toString().contains(UP_SUBST_PREFIX);
  }

  /**
   * Interface used for parsing specific chunks of the gadget spec
   */
  interface ElementVisitor {
    /**
     * Called on each node that matches
     *
     * @param tag the name of the tag being parsed
     * @param element the element to parse
     * @return true if we handled the tag, false if not
     * @throws SpecParserException when parsing issues are present
     */
    boolean visit(String tag, Element element) throws SpecParserException;

    /**
     * Called when all elements have been processed.  Any data that is set on the ModulePrefs instance should be
     * Immutable
     *
     * @param moduleprefs The moduleprefs object to mutate
     */
    void apply(ModulePrefs moduleprefs);
  }

  /**
   * Processes ModulePrefs/Preload into a list.
   */
  private class PreloadVisitor implements ElementVisitor {
    private final List preloaded = Lists.newLinkedList();

    public boolean visit(String tag,Element element) throws SpecParserException {
      if (!"Preload".equals(tag)) return false;

      Preload preload = new Preload(element, base);
      preloaded.add(preload);
      return true;
    }

    public void apply(ModulePrefs moduleprefs) {
      moduleprefs.preloads = ImmutableList.copyOf(preloaded);
    }
  }

  /**
   * Process ModulePrefs/OAuth
   */
  private final class OAuthVisitor implements ElementVisitor {
    private OAuthSpec oauthSpec = null;
    private final MutableBoolean oauthMarker;
    
    private OAuthVisitor(MutableBoolean oauthMarker) {
      this.oauthMarker = oauthMarker;
    }

    public boolean visit(String tag, Element element) throws SpecParserException {
      if (!"OAuth".equals(tag)) return false;

      if (oauthSpec != null) {
        throw new SpecParserException("ModulePrefs/OAuth may only occur once.");
      }
      oauthSpec = new OAuthSpec(element, base);
      oauthMarker.setValue(true);
      return true;
    }

    public void apply(ModulePrefs moduleprefs) {
      moduleprefs.oauth = oauthSpec;
    }

  }
  
  /**
   * Process ModulePrefs/OAuth2
   */
  private final class OAuth2Visitor implements ElementVisitor {
    private OAuth2Spec oauth2Spec = null;
    private final MutableBoolean oauth2Marker;
    
    private OAuth2Visitor(MutableBoolean oauth2Marker) {
      this.oauth2Marker = oauth2Marker;
    }

    public boolean visit(String tag, Element element) throws SpecParserException {
      if (!"OAuth2".equals(tag)) return false;

      if (oauth2Spec != null) {
        throw new SpecParserException("ModulePrefs/OAuth2 may only occur once.");
      }
      oauth2Spec = new OAuth2Spec(element, base);
      oauth2Marker.setValue(true);
      return true;
    }

    public void apply(ModulePrefs moduleprefs) {
      moduleprefs.oauth2 = oauth2Spec;
    }

  }

  /**
   * Processes ModulePrefs/Require and ModulePrefs/Optional
   */
  private static final class FeatureVisitor implements ElementVisitor {
    private final Map features = Maps.newHashMap();
    private final Map globalFeatures = Maps.newHashMap();
    private final MutableBoolean oauthMarker;
    private boolean coreIncluded = false;

    private static final Set TAGS = ImmutableSet.of("Require", "Optional");
    
    private FeatureVisitor(MutableBoolean oauthMarker) {
      this.oauthMarker = oauthMarker;
    }

    public boolean visit(String tag, Element element)
        throws SpecParserException {
      if (!TAGS.contains(tag))
        return false;

      Feature feature = new Feature(element);
      if (feature.getViews().isEmpty()) {
        coreIncluded = coreIncluded || feature.getName().startsWith("core");
        features.put(feature.getName(), feature);
        globalFeatures.put(feature.getName(), feature);
      } else {
        // We are going to include Core feature globally, so skip it if it was
        // included for any Views
        if (!feature.getName().startsWith("core")) {
          // Key view level features by qualifying with the view ID
          for (String view : feature.getViews()) {
            StringBuilder buff = new StringBuilder(feature.getName());
            buff.append('.');
            buff.append(view);
            features.put(buff.toString(), feature);
          }
        }
      }
      return true;
    }
    
    public void apply(ModulePrefs moduleprefs) {
      if (!coreIncluded) {
        // No library was explicitly included from core - add it as an implicit dependency.
        features.put(Feature.CORE_FEATURE.getName(), Feature.CORE_FEATURE);
        globalFeatures.put(Feature.CORE_FEATURE.getName(), Feature.CORE_FEATURE);
      }
      if (oauthMarker.booleanValue()) {
        // / tag found: security token needed.
        features.put(Feature.SECURITY_TOKEN_FEATURE.getName(), Feature.SECURITY_TOKEN_FEATURE);
        globalFeatures.put(Feature.SECURITY_TOKEN_FEATURE.getName(), Feature.SECURITY_TOKEN_FEATURE);
      }
      moduleprefs.features = ImmutableMap.copyOf(features);
      moduleprefs.globalFeatures = ImmutableMap.copyOf(globalFeatures);
      moduleprefs.allFeatures = ImmutableList.copyOf(features.values());
    }
  }

  /**
   * Processes ModulePrefs/Icon
   */
  private static class IconVisitor implements ElementVisitor {
    private final List icons = Lists.newLinkedList();

    public boolean visit(String tag, Element element) throws SpecParserException {
      if (!"Icon".equals(tag)) return false;

      icons.add(new Icon(element));
      return true;
    }
    public void apply(ModulePrefs moduleprefs) {
      moduleprefs.icons = ImmutableList.copyOf(icons);
    }
  }

  /**
   * Process ModulePrefs/Locale
   */
  private class LocaleVisitor implements ElementVisitor {

    private Map> locales = Maps.newHashMap();

    public boolean visit(String tag, Element element)
        throws SpecParserException {
      if (!"Locale".equals(tag))
        return false;
      LocaleSpec locale = new LocaleSpec(element, base);
      if (locale.getViews().isEmpty()) {
        storeLocaleSpec(GLOBAL_LOCALE, locale);
      } else {
        // We've got a view level Locale, need to store the mapping of Views to
        // the appropriate LocaleSpecs
        for (String view : locale.getViews()) {
          storeLocaleSpec(view,locale);
        }
      }
      return true;
    }
    
    public void apply(ModulePrefs moduleprefs) {
      Map allLocales = Maps.newHashMap();
      moduleprefs.locales = locales;
      for(Map map : locales.values()){
        allLocales.putAll(map);
      }
      moduleprefs.allLocales = ImmutableMap.copyOf(allLocales);
    }
    
    private void storeLocaleSpec(String view, LocaleSpec locale){
      Map viewLocaleSpecs;
      if (locales.get(view) == null) {
        viewLocaleSpecs = Maps.newHashMap();
        locales.put(view, viewLocaleSpecs);
      } else {
        viewLocaleSpecs = locales.get(view);
      }
      viewLocaleSpecs.put(new Locale(locale.getLanguage(), locale.getCountry()), locale);      
    }
    
  }

  /**
   * Process ModulePrefs/Link
   */
  private class LinkVisitor implements ElementVisitor {
    private final Map linkMap = Maps.newHashMap();

    public boolean visit(String tag, Element element) throws SpecParserException {
      if (!"Link".equals(tag)) return false;
      LinkSpec link = new LinkSpec(element, base);
      linkMap.put(link.getRel(), link);
      return true;
    }

    public void apply(ModulePrefs moduleprefs) {
      moduleprefs.links = ImmutableMap.copyOf(linkMap);
    }
  }

  private static class ExtraElementsVisitor implements ElementVisitor {
    private Multimap elements = ArrayListMultimap.create();

    public boolean visit(String tag, Element element) throws SpecParserException {
      elements.put(tag, element.cloneNode(true));
      return true;
    }
    public void apply(ModulePrefs moduleprefs) {
      moduleprefs.extraElements = ImmutableMultimap.copyOf(elements);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy