Package org.apache.shindig.gadgets.templates

Source Code of org.apache.shindig.gadgets.templates.XmlTemplateLibrary$LibraryTagHandler

/*
* 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.templates;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;

import org.apache.commons.lang3.StringUtils;
import org.apache.shindig.common.uri.Uri;
import org.apache.shindig.common.xml.DomUtil;
import org.apache.shindig.gadgets.GadgetException;
import org.apache.shindig.gadgets.render.SanitizingGadgetRewriter;
import org.apache.shindig.gadgets.templates.tags.DefaultTagRegistry;
import org.apache.shindig.gadgets.templates.tags.TagHandler;
import org.apache.shindig.gadgets.templates.tags.TemplateBasedTagHandler;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.util.Set;

/**
* An Object representing a Library of Template-based custom OSML tags.
*/
public class XmlTemplateLibrary implements TemplateLibrary {

  public static final String TAG_ATTRIBUTE = "tag";
  public static final String NAMESPACE_TAG = "Namespace";
  public static final String TEMPLATE_TAG = "Template";
  public static final String STYLE_TAG = "Style";
  public static final String JAVASCRIPT_TAG = "JavaScript";
  public static final String TEMPLATEDEF_TAG = "TemplateDef";

  private final Uri libraryUri;
  private final String source;
  private final boolean safe;
  private final TagRegistry registry;
  private String nsPrefix;
  private String nsUri;
  private String style;
  private String javaScript;
  private final Set<TemplateResource> libraryResources;

  /**
   * @param uri URI of the template library
   * @param root Element representing the Templates tag of this library
   */
  public XmlTemplateLibrary(Uri uri, Element root, String source)
      throws GadgetException {
    this(uri, root, source, false);
  }

  /**
   * @param uri URI of the template library
   * @param root Element representing the Templates tag of this library
   * @param safe Is this library exempt from being sanitized?
   */
  public XmlTemplateLibrary(Uri uri, Element root, String source, boolean safe)
      throws GadgetException {
    this.libraryUri = uri;
    this.source = source;
    this.safe = safe;
    this.registry = new DefaultTagRegistry(parseLibraryDocument(root));
    ImmutableSet.Builder<TemplateResource> resources = ImmutableSet.builder();
    if (style != null) {
      resources.add(TemplateResource.newStyleResource(style, this));
    }
    if (javaScript != null) {
      resources.add(TemplateResource.newJavascriptResource(javaScript, this));
    }

    this.libraryResources = resources.build();
  }

  /**
   * @return a registry of tags in this library.
   */
  public TagRegistry getTagRegistry() {
    return registry;
  }

  /**
   * @return the URI from which the library was loaded.  (This is not the
   * namespace of tags in the library.)
   */
  public Uri getLibraryUri() {
    return libraryUri;
  }

  /**
   * @return this library is safe and its content doesn't need to be sanitized.
   */
  public boolean isSafe() {
    return safe;
  }

  /**
   * @return This library as XML source.
   */
  public String serialize() {
    return source;
  }

  /**
   * Creates a tag handler wrapping an element.  By default, creates
   * a {@link TemplateBasedTagHandler}.  Override this to create custom
   * tag handlers.
   */
  protected TagHandler createTagHandler(Element template, String namespaceUri,
      String localName) {
    return new TemplateBasedTagHandler(template, namespaceUri, localName);
  }

  private Set<TagHandler> parseLibraryDocument(Element root) throws GadgetException {
    ImmutableSet.Builder<TagHandler> handlers = ImmutableSet.builder();
    Node childNode = root.getFirstChild();
    while(childNode != null) {
      if (!(childNode instanceof Element)) {
        childNode = childNode.getNextSibling();
        continue;
      }
      Element element = (Element) childNode;
      if (NAMESPACE_TAG.equals(element.getLocalName())) {
        processNamespace(element);
      } else if (STYLE_TAG.equals(element.getLocalName())) {
        processStyle(element);
      } else if (JAVASCRIPT_TAG.equals(element.getLocalName())) {
        processJavaScript(element);
      } else if (TEMPLATE_TAG.equals(element.getLocalName())) {
        processTemplate(handlers, element);
      } else if (TEMPLATEDEF_TAG.equals(element.getLocalName())) {
        processTemplateDef(handlers, element);
      }
      childNode = childNode.getNextSibling();
    }

    return handlers.build();
  }

  private void processTemplateDef(Builder<TagHandler> handlers, Element defElement)
      throws TemplateParserException {
    Attr tagAttribute = null;
    synchronized (defElement) {
      tagAttribute =  defElement.getAttributeNode(TAG_ATTRIBUTE);
      if (tagAttribute == null) {
        throw new TemplateParserException("Missing tag attribute on TemplateDef");
      }
    }
    ImmutableSet.Builder<TemplateResource> resources = ImmutableSet.builder();

    Element scriptElement = (Element) DomUtil.getFirstNamedChildNode(defElement, JAVASCRIPT_TAG);
    if (scriptElement != null) {
      resources.add(TemplateResource.newJavascriptResource(scriptElement.getTextContent(), this));
    }

    Element styleElement = (Element) DomUtil.getFirstNamedChildNode(defElement, STYLE_TAG);
    if (styleElement != null) {
      resources.add(TemplateResource.newStyleResource(styleElement.getTextContent(), this));
    }

    Element templateElement = (Element) DomUtil.getFirstNamedChildNode(defElement, TEMPLATE_TAG);
    TagHandler handler = createHandler(tagAttribute.getNodeValue(), templateElement,
        resources.build());
    if (handler != null) {
      handlers.add(handler);
    }
  }

  private void processTemplate(Builder<TagHandler> handlers, Element templateElement)
      throws TemplateParserException {
    Attr tagAttribute = templateElement.getAttributeNode(TAG_ATTRIBUTE);
    if (tagAttribute == null) {
      throw new TemplateParserException("Missing tag attribute on Template");
    }

    TagHandler handler = createHandler(tagAttribute.getNodeValue(), templateElement,
        ImmutableSet.<TemplateResource>of());
    if (handler != null) {
      handlers.add(handler);
    }
  }

  private void processStyle(Element element) {
    if (style == null) {
      style = element.getTextContent();
    } else {
      style = style + '\n' + element.getTextContent();
    }
  }

  private void processJavaScript(Element element) {
    if (javaScript == null) {
      javaScript = element.getTextContent();
    } else {
      javaScript = javaScript + '\n' + element.getTextContent();
    }
  }

  private void processNamespace(Element namespaceNode) throws TemplateParserException {
    if ((nsPrefix != null) || (nsUri != null)) {
      throw new TemplateParserException("Duplicate Namespace elements");
    }
    synchronized (namespaceNode) {
      nsPrefix = namespaceNode.getAttribute("prefix");
      if ("".equals(nsPrefix)) {
        throw new TemplateParserException("Missing prefix attribute on Namespace");
      }

      nsUri = namespaceNode.getAttribute("url");
      if ("".equals(nsUri)) {
        throw new TemplateParserException("Missing url attribute on Namespace");
      }
    }
  }

  private TagHandler createHandler(String tagName, Element template,
      Set<TemplateResource> resources)
      throws TemplateParserException {
    String [] nameParts = StringUtils.splitPreserveAllTokens(tagName, ':');
    // At this time, we only support namespaced tags
    if (nameParts.length != 2) {
      return null;
    }
    String namespaceUri = "";
    synchronized (template) {
      namespaceUri = template.lookupNamespaceURI(nameParts[0]);
    }
    if (!nsPrefix.equals(nameParts[0]) || !nsUri.equals(namespaceUri)) {
      throw new TemplateParserException(
          "Can't create tags in undeclared namespace: " + nameParts[0]);
    }

    if (isSafe()) {
      bypassTemplateSanitization(template);
    }

    return new LibraryTagHandler(
        createTagHandler(template, namespaceUri, nameParts[1]),
        resources);
  }

  /**
   * For "safe" libraries, bypass sanitization.  Sanitization should
   * be bypassed on each element in the tree, but not on the whole
   * tree (false, not true, in the call to bypassSanitization() below),
   * since os:Render elements will insert unsafe content.
   */
  private void bypassTemplateSanitization(Element template) {
    SanitizingGadgetRewriter.bypassSanitization(template, false);
    Node childNode = template.getFirstChild();
    while(childNode != null) {
      if (childNode instanceof Element) {
        bypassTemplateSanitization((Element) childNode);
      }
      childNode = childNode.getNextSibling();
    }
  }

  /**
   * TagHandler delegate reponsible for adding necessary tag resources
   * as each tag gets processed.
   */
  private class LibraryTagHandler implements TagHandler {
    private final TagHandler tagHandler;
    private final Set<TemplateResource> tagResources;

    public LibraryTagHandler(TagHandler tagHandler, Set<TemplateResource> resources) {
      this.tagHandler = tagHandler;
      tagResources = resources;
    }

    public String getNamespaceUri() {
      return tagHandler.getNamespaceUri();
    }

    public String getTagName() {
      return tagHandler.getTagName();
    }

    public void process(Node result, Element tag, TemplateProcessor processor) {
      // Add all template resources and library resources.  Use the resource
      // instance as its own key, since we're careful to create the resource
      // objects once.  NOTE: this assumes that TemplateResource uses instance
      // equality, not value equality.
      for (TemplateResource resource : tagResources) {
        processor.getTemplateContext().addResource(resource, resource);
      }

      for (TemplateResource resource : libraryResources) {
        processor.getTemplateContext().addResource(resource, resource);
      }

      tagHandler.process(result, tag, processor);
    }
  }
}
TOP

Related Classes of org.apache.shindig.gadgets.templates.XmlTemplateLibrary$LibraryTagHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.