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

org.apache.shindig.gadgets.parse.caja.CajaCssParser Maven / Gradle / Ivy

Go to download

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

There is a newer version: 3.0.0-beta4
Show 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.parse.caja;

import org.apache.shindig.common.cache.Cache;
import org.apache.shindig.common.cache.CacheProvider;
import org.apache.shindig.common.util.HashUtil;
import org.apache.shindig.gadgets.GadgetException;

import com.google.caja.lexer.CharProducer;
import com.google.caja.lexer.CssLexer;
import com.google.caja.lexer.CssTokenType;
import com.google.caja.lexer.InputSource;
import com.google.caja.lexer.ParseException;
import com.google.caja.lexer.Token;
import com.google.caja.lexer.TokenQueue;
import com.google.caja.lexer.TokenStream;
import com.google.caja.parser.css.CssParser;
import com.google.caja.parser.css.CssTree;
import com.google.caja.render.Concatenator;
import com.google.caja.render.CssPrettyPrinter;
import com.google.caja.reporting.MessageLevel;
import com.google.caja.reporting.MessageQueue;
import com.google.caja.reporting.RenderContext;
import com.google.caja.reporting.SimpleMessageQueue;
import com.google.caja.util.Criterion;
import com.google.inject.Inject;

import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URI;
import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;

/** A CSS DOM parser using Caja. */
public class CajaCssParser {

  private static final Logger log = Logger.getLogger(CajaCssParser.class.getName());

  /**
   * Dummy URI that is never read from. Needed to construct Caja parser
   */
  private static final URI FAKE_SOURCE = URI.create("http://a.dummy.url");

  // Switch to "parsedCss" once CajaCssLexerParser is removed. See ehCacheConfig
  private static final String PARSED_CSS = "parsedCssDom";

  private Cache parsedCssCache;

  @Inject
  public void setCacheProvider(CacheProvider cacheProvider) {
    parsedCssCache = cacheProvider.createCache(PARSED_CSS);
  }

  /**
   * Parse CSS content into Caja's CSS DOM model
   *
   * @return A parsed stylesheet
   */
  public CssTree.StyleSheet parseDom(String content) throws GadgetException {
    CssTree.StyleSheet parsedCss = null;
    boolean shouldCache = shouldCache();
    String key = null;
    if (shouldCache) {
      // TODO - Consider using the source if its under a certain size
      key = HashUtil.rawChecksum(content.getBytes());
      parsedCss = parsedCssCache.getElement(key);
    }
    if (parsedCss == null) {
      try {
        parsedCss = parseImpl(content);
        if (shouldCache) {
          parsedCssCache.addElement(key, parsedCss);
        }
      } catch (ParseException pe) {
        throw new GadgetException(GadgetException.Code.CSS_PARSE_ERROR, pe);
      }
    }
    if (shouldCache) {
      return (CssTree.StyleSheet)parsedCss.clone();
    }
    return parsedCss;
  }

  private CssTree.StyleSheet parseImpl(String css) throws ParseException {
    InputSource inputSource = new InputSource(FAKE_SOURCE);
    CharProducer producer = CharProducer.Factory.create(new StringReader(css),
        inputSource);
    TokenStream lexer = new CssLexer(producer);
    TokenQueue queue = new TokenQueue(lexer, inputSource,
        new Criterion>() {
          public boolean accept(Token t) {
            return CssTokenType.SPACE != t.type
                && CssTokenType.COMMENT != t.type;
          }
        });
    if (queue.isEmpty()) {
      // Return empty stylesheet
      return new CssTree.StyleSheet(null, Collections.emptyList());
    }
    MessageQueue mq = new SimpleMessageQueue();
    CssParser parser = new CssParser(queue, mq, MessageLevel.WARNING);
    return parser.parseStyleSheet();
  }

  /** Serialize a stylesheet to a String */
  public String serialize(CssTree.StyleSheet styleSheet) {
    StringWriter writer = new StringWriter();
    serialize(styleSheet, writer);
    return writer.toString();
  }

  /** Serialize a stylesheet to a Writer. */
  public void serialize(CssTree.StyleSheet styleSheet, Writer writer) {
    CssPrettyPrinter cssPrinter = new CssPrettyPrinter(new Concatenator(writer, null));
    styleSheet.render(new RenderContext(cssPrinter));
    cssPrinter.noMoreTokens();
  }

  private boolean shouldCache() {
    return parsedCssCache != null && parsedCssCache.getCapacity() != 0;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy