You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by lr...@apache.org on 2008/11/07 08:35:00 UTC

svn commit: r712080 - in /incubator/shindig/trunk/java: common/src/main/java/org/apache/shindig/common/xml/ gadgets/src/main/java/org/apache/shindig/gadgets/parse/ gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/ gadgets/src/main/java/org/a...

Author: lryan
Date: Thu Nov  6 23:34:51 2008
New Revision: 712080

URL: http://svn.apache.org/viewvc?rev=712080&view=rev
Log:
Greatly simplify MutableContent
Fix misc issues in rewriter registry
Added ContentRewriterRegistry.rewrite(Gadget g, View v)
Parsers now ensure document always contains a HEAD element

Added:
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/DomUtil.java
Modified:
    incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/xml/XmlUtil.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/HtmlSerializer.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParser.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoSimplifiedHtmlParser.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/CachingContentRewriterRegistry.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterRegistry.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DefaultContentRewriterRegistry.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/JsTagConcatContentRewriter.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/LinkingTagContentRewriter.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/MutableContent.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriterUtils.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleLinksContentRewriter.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/HtmlParserTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/nekohtml/NekoSimplifiedHtmlParserTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/HtmlRendererTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingContentRewriterTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/BaseRewriterTestCase.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/DefaultContentRewriterRegistryTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/JsTagConcatContentRewriterTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/LexerVsDomRewriteBenchmark.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/LinkingTagContentRewriterTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/MutableContentTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleLinksContentRewriterTest.java

Modified: incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/xml/XmlUtil.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/xml/XmlUtil.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/xml/XmlUtil.java (original)
+++ incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/xml/XmlUtil.java Thu Nov  6 23:34:51 2008
@@ -18,7 +18,6 @@
 package org.apache.shindig.common.xml;
 
 import org.apache.shindig.common.uri.Uri;
-
 import org.w3c.dom.Element;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
@@ -27,15 +26,14 @@
 import org.xml.sax.SAXException;
 import org.xml.sax.SAXParseException;
 
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
 import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 /**
  * Utility class for simplifying parsing of xml documents. Documents are not validated, and
@@ -266,20 +264,6 @@
   }
 
   /**
-   * @return first child node matching the specified name
-   */
-  public static Node getFirstNamedChildNode(Node root, String nodeName) {
-    Node current = root.getFirstChild();
-    while (current != null) {
-      if (current.getNodeName().equalsIgnoreCase(nodeName)) {
-        return current;
-      }
-      current = current.getNextSibling();
-    }
-    return null;
-  }
-
-  /**
    * Fetch a builder from the pool, creating a new one only if necessary.
    */
   private static DocumentBuilder getBuilder() throws ParserConfigurationException {

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/DomUtil.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/DomUtil.java?rev=712080&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/DomUtil.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/DomUtil.java Thu Nov  6 23:34:51 2008
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+import com.google.common.collect.Lists;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.traversal.DocumentTraversal;
+import org.w3c.dom.traversal.NodeFilter;
+import org.w3c.dom.traversal.NodeIterator;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Utility functions for navigating DOM
+ */
+public class DomUtil {
+  /**
+   * @return first child node matching the specified name
+   */
+  public static Node getFirstNamedChildNode(Node root, String nodeName) {
+    Node current = root.getFirstChild();
+    while (current != null) {
+      if (current.getNodeName().equalsIgnoreCase(nodeName)) {
+        return current;
+      }
+      current = current.getNextSibling();
+    }
+    return null;
+  }
+
+  public static List<Node> getElementsByTagNameCaseInsensitive(Document doc,
+      final Set<String> lowerCaseNames) {
+    final List<Node> result = Lists.newArrayList();
+    NodeIterator nodeIterator = ((DocumentTraversal) doc)
+        .createNodeIterator(doc, NodeFilter.SHOW_ELEMENT,
+            new NodeFilter() {
+              public short acceptNode(Node n) {
+                if (lowerCaseNames.contains(n.getNodeName().toLowerCase())) {
+                  return NodeFilter.FILTER_ACCEPT;
+                }
+                return NodeFilter.FILTER_REJECT;
+              }
+            }, false);
+    for (Node n = nodeIterator.nextNode(); n != null ; n = nodeIterator.nextNode()) {
+      result.add(n);
+    }
+    return result;
+  }
+}

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java Thu Nov  6 23:34:51 2008
@@ -42,10 +42,22 @@
     return normalized.contains("<!DOCTYPE") || normalized.contains("<HTML");
   }
 
+  public final Document parseDom(String source) throws GadgetException {
+    Document document = parseDomImpl(source);
+    // Ensure head tag exists
+    if (DomUtil.getFirstNamedChildNode(document.getDocumentElement(), "head") == null) {
+      // Add as first element
+      document.getDocumentElement().insertBefore(
+          document.createElement("head"),
+          document.getDocumentElement().getFirstChild());
+    }
+    return document;
+  }
+
   /**
    * @param source
    * @return a parsed document or document fragment
    * @throws GadgetException
    */
-  public abstract Document parseDom(String source) throws GadgetException;
+  protected abstract Document parseDomImpl(String source) throws GadgetException;
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/HtmlSerializer.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/HtmlSerializer.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/HtmlSerializer.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/HtmlSerializer.java Thu Nov  6 23:34:51 2008
@@ -54,11 +54,21 @@
   }
 
   /**
+   * Copy serializer from one document to another. Note this requires that
+   * serializers are thread safe
+   */
+  public static void copySerializer(Document from, Document to) {
+    Integer length = (Integer)from.getUserData(ORIGINAL_LENGTH);
+    if (length != null) to.setUserData(ORIGINAL_LENGTH, length, null);
+    to.setUserData(KEY, from.getUserData(KEY), null);
+  }
+
+  /**
    * Get the length of the original version of the document
    * @param doc
    * @return
    */
-  protected static int getOriginalLength(Document doc) {
+  private static int getOriginalLength(Document doc) {
     Integer length = (Integer)doc.getUserData(ORIGINAL_LENGTH);
     if (length == null) return -1;
     return length;

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParser.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParser.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParser.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/caja/CajaHtmlParser.java Thu Nov  6 23:34:51 2008
@@ -51,7 +51,7 @@
   }
 
   @Override
-  public Document parseDom(String source) throws GadgetException {
+  public Document parseDomImpl(String source) throws GadgetException {
     // Wrap the whole thing in a top-level node to get full contents.
     Document document = makeDocument(getFragment(source));
     HtmlSerializer.attach(document, new Serializer(), source);

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java Thu Nov  6 23:34:51 2008
@@ -18,8 +18,8 @@
 package org.apache.shindig.gadgets.parse.nekohtml;
 
 import com.google.inject.Inject;
-import org.apache.shindig.common.xml.XmlUtil;
 import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.parse.DomUtil;
 import org.apache.shindig.gadgets.parse.GadgetHtmlParser;
 import org.apache.shindig.gadgets.parse.HtmlSerializer;
 import org.apache.xml.serialize.HTMLSerializer;
@@ -54,7 +54,7 @@
   }
 
   @Override
-  public Document parseDom(String source) throws GadgetException {
+  public Document parseDomImpl(String source) throws GadgetException {
     try {
       Document document = parseFragment(source);
       HtmlSerializer.attach(document, new Serializer(), source);
@@ -71,7 +71,7 @@
     Document htmlDoc = documentProvider.createDocument(null, null, null);
     DocumentFragment fragment = htmlDoc.createDocumentFragment();
     parser.parse(input, fragment);
-    Node htmlNode = XmlUtil.getFirstNamedChildNode(fragment, "HTML");
+    Node htmlNode = DomUtil.getFirstNamedChildNode(fragment, "HTML");
     if (htmlNode != null) {
       htmlDoc.appendChild(htmlNode);
     } else {

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoSimplifiedHtmlParser.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoSimplifiedHtmlParser.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoSimplifiedHtmlParser.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoSimplifiedHtmlParser.java Thu Nov  6 23:34:51 2008
@@ -20,7 +20,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.inject.Inject;
-import org.apache.shindig.common.xml.XmlUtil;
+import org.apache.shindig.gadgets.parse.DomUtil;
 import org.apache.shindig.gadgets.parse.GadgetHtmlParser;
 import org.apache.shindig.gadgets.parse.HtmlSerializer;
 import org.apache.xerces.xni.*;
@@ -58,7 +58,8 @@
     this.documentFactory = documentFactory;
   }
 
-  public Document parseDom(String source) {
+  @Override
+  protected Document parseDomImpl(String source) {
 
     HTMLScanner htmlScanner = new HTMLScanner();
     HTMLTagBalancer tagBalancer = new HTMLTagBalancer();
@@ -76,7 +77,7 @@
       htmlScanner.scanDocument(true);
       Document document = handler.getDocument();
       DocumentFragment fragment = handler.getFragment();
-      Node htmlNode = XmlUtil.getFirstNamedChildNode(fragment, "HTML");
+      Node htmlNode = DomUtil.getFirstNamedChildNode(fragment, "HTML");
       if (htmlNode != null) {
         document.appendChild(htmlNode);
       } else {

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/CachingContentRewriterRegistry.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/CachingContentRewriterRegistry.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/CachingContentRewriterRegistry.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/CachingContentRewriterRegistry.java Thu Nov  6 23:34:51 2008
@@ -17,17 +17,18 @@
  */
 package org.apache.shindig.gadgets.rewrite;
 
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
 import org.apache.shindig.common.cache.CacheProvider;
 import org.apache.shindig.common.cache.TtlCache;
 import org.apache.shindig.common.util.HashUtil;
 import org.apache.shindig.gadgets.Gadget;
+import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.http.HttpRequest;
 import org.apache.shindig.gadgets.http.HttpResponse;
 import org.apache.shindig.gadgets.http.HttpResponseBuilder;
 import org.apache.shindig.gadgets.parse.GadgetHtmlParser;
-
-import com.google.inject.Inject;
-import com.google.inject.name.Named;
+import org.apache.shindig.gadgets.spec.View;
 
 import java.util.List;
 
@@ -88,6 +89,40 @@
     return rewritersKey;
   }
 
+  public String rewriteGadget(Gadget gadget, View currentView) throws GadgetException {
+    if (gadget.getContext().getIgnoreCache()) {
+      return super.rewriteGadget(gadget, currentView);
+    }
+
+    String cacheKey = getGadgetCacheKey(gadget, currentView.getContent());
+    String cached = rewrittenCache.getElement(cacheKey);
+
+    if (cached != null) {
+      return cached;
+    }
+
+    MutableContent mc = getMutableContent(gadget.getSpec(), currentView);
+
+    long cacheTtl = Long.MAX_VALUE;
+    for (ContentRewriter rewriter : getRewriters()) {
+      RewriterResults rr = rewriter.rewrite(gadget, mc);
+      if (rr == null) {
+        cacheTtl = 0;
+      } else {
+        cacheTtl = Math.min(cacheTtl, rr.getCacheTtl());
+      }
+    }
+
+    if (cacheTtl >= minCacheTtl) {
+      // Only cache if the cacheTtl is greater than the minimum time configured for doing so.
+      // This prevents cache churn and may be more efficient when rewriting is cheaper
+      // than a cache lookup.
+      rewrittenCache.addElementWithTtl(cacheKey, currentView.getContent(), cacheTtl);
+    }
+
+    return mc.getContent();
+  }
+
   /** {@inheritDoc} */
   @Override
   public String rewriteGadget(Gadget gadget, String content) {
@@ -101,7 +136,6 @@
     if (cached != null) {
       return cached;
     }
-
     MutableContent mc = getMutableContent(content);
 
     long cacheTtl = Long.MAX_VALUE;
@@ -121,7 +155,7 @@
       rewrittenCache.addElementWithTtl(cacheKey, content, cacheTtl);
     }
 
-    return content;
+    return mc.getContent();
   }
 
   /** {@inheritDoc} */

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterRegistry.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterRegistry.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterRegistry.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterRegistry.java Thu Nov  6 23:34:51 2008
@@ -17,18 +17,28 @@
  */
 package org.apache.shindig.gadgets.rewrite;
 
+import com.google.inject.ImplementedBy;
 import org.apache.shindig.gadgets.Gadget;
 import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.http.HttpRequest;
 import org.apache.shindig.gadgets.http.HttpResponse;
-
-import com.google.inject.ImplementedBy;
+import org.apache.shindig.gadgets.spec.View;
 
 /**
  * Performs rewriting operations by invoking one or more ContentRewriters.
  */
 @ImplementedBy(DefaultContentRewriterRegistry.class)
 public interface ContentRewriterRegistry {
+
+  /**
+   * Rewrites a {@code Gadget} object given the registered rewriters.
+   * @param gadget Gadget object to use as a rewriting context.
+   * @param currentView The gadget view to rewrite
+   * @return The rewritten content.
+   * @throws GadgetException Potentially passed through from rewriters
+   */
+  String rewriteGadget(Gadget gadget, View currentView) throws GadgetException;
+
   /**
    * Rewrites a {@code Gadget} object given the registered rewriters.
    * @param gadget Gadget object to use as a rewriting context.

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DefaultContentRewriterRegistry.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DefaultContentRewriterRegistry.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DefaultContentRewriterRegistry.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/DefaultContentRewriterRegistry.java Thu Nov  6 23:34:51 2008
@@ -17,13 +17,15 @@
  */
 package org.apache.shindig.gadgets.rewrite;
 
+import com.google.inject.Inject;
 import org.apache.shindig.gadgets.Gadget;
+import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.http.HttpRequest;
 import org.apache.shindig.gadgets.http.HttpResponse;
 import org.apache.shindig.gadgets.http.HttpResponseBuilder;
 import org.apache.shindig.gadgets.parse.GadgetHtmlParser;
-
-import com.google.inject.Inject;
+import org.apache.shindig.gadgets.spec.GadgetSpec;
+import org.apache.shindig.gadgets.spec.View;
 
 import java.util.Collections;
 import java.util.LinkedList;
@@ -31,8 +33,6 @@
 
 /**
  * Basic registry -- just iterates over rewriters and invokes them sequentially.
- *
- * TODO: Make abstract and bind CachingContentRewriterRegistry as the default.
  */
 public class DefaultContentRewriterRegistry implements ContentRewriterRegistry {
   protected final List<ContentRewriter> rewriters;
@@ -49,6 +49,20 @@
   }
 
   /** {@inheritDoc} */
+  public String rewriteGadget(Gadget gadget, View currentView) throws GadgetException {
+    if (currentView == null) {
+      // Nothing to rewrite.
+      return null;
+    }
+    MutableContent mc = getMutableContent(gadget.getSpec(), currentView);
+
+    for (ContentRewriter rewriter : rewriters) {
+      rewriter.rewrite(gadget, mc);
+    }
+    return mc.getContent();
+  }
+
+  /** {@inheritDoc} */
   public String rewriteGadget(Gadget gadget, String content) {
     if (content == null) {
       // Nothing to rewrite.
@@ -58,7 +72,6 @@
     MutableContent mc = getMutableContent(content);
 
     for (ContentRewriter rewriter : rewriters) {
-      mc.getContent();
       rewriter.rewrite(gadget, mc);
     }
 
@@ -83,8 +96,13 @@
   }
 
   protected MutableContent getMutableContent(String content) {
-    MutableContent mc = new MutableContent(htmlParser);
-    mc.setContent(content);
+    MutableContent mc = new MutableContent(htmlParser, content, null);
+    return mc;
+  }
+
+  protected MutableContent getMutableContent(GadgetSpec spec, View v) throws GadgetException {
+    // TODO - Consider using caching here to avoid parse costs
+    MutableContent mc = new MutableContent(htmlParser, v.getContent(), null);
     return mc;
   }
 

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/JsTagConcatContentRewriter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/JsTagConcatContentRewriter.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/JsTagConcatContentRewriter.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/JsTagConcatContentRewriter.java Thu Nov  6 23:34:51 2008
@@ -27,6 +27,7 @@
 import org.apache.shindig.gadgets.Gadget;
 import org.apache.shindig.gadgets.http.HttpRequest;
 import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.parse.DomUtil;
 import org.apache.shindig.gadgets.servlet.ProxyBase;
 import org.apache.shindig.gadgets.spec.View;
 import org.w3c.dom.Node;
@@ -88,7 +89,7 @@
 
     // Get all the script tags
     List<Node> nodeList =
-        RewriterUtils.getElementsByTagNameCaseInsensitive(content.getDocument(), TAG_NAMES);
+        DomUtil.getElementsByTagNameCaseInsensitive(content.getDocument(), TAG_NAMES);
 
     boolean mutated = false;
     List<Node> concatenateable = new ArrayList<Node>();

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/LinkingTagContentRewriter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/LinkingTagContentRewriter.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/LinkingTagContentRewriter.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/LinkingTagContentRewriter.java Thu Nov  6 23:34:51 2008
@@ -26,6 +26,7 @@
 import org.apache.shindig.gadgets.Gadget;
 import org.apache.shindig.gadgets.http.HttpRequest;
 import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.parse.DomUtil;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 
@@ -45,7 +46,7 @@
   }
 
   private final ContentRewriterFeatureFactory rewriterFactory;
-  private String proxyUrl;
+  private final String proxyUrl;
 
   @Inject
   public LinkingTagContentRewriter(ContentRewriterFeatureFactory rewriterFactory,
@@ -73,7 +74,7 @@
 
     Set<String> tags = SUPPORTED_TAG_ATTRS.keySet();
     tags.retainAll(feature.getIncludedTags());
-    List<Node> nodes = RewriterUtils.getElementsByTagNameCaseInsensitive(
+    List<Node> nodes = DomUtil.getElementsByTagNameCaseInsensitive(
         content.getDocument(), tags);
 
     for (Node node : nodes) {

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/MutableContent.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/MutableContent.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/MutableContent.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/MutableContent.java Thu Nov  6 23:34:51 2008
@@ -29,23 +29,32 @@
 public class MutableContent {
   private String content;
   private Document document;
-  private ContentEditListener editListener;
-  private int parseEditId;
-  private int contentParseId;
   private final GadgetHtmlParser contentParser;
 
   private static final String MUTABLE_CONTENT_LISTENER = "MutableContentListener";
 
   public static void notifyEdit(Document doc) {
-    ContentEditListener listener = (ContentEditListener)doc.getUserData(MUTABLE_CONTENT_LISTENER);
-    if (listener != null) {
-      listener.nodeEdited();
+    MutableContent mc = (MutableContent) doc.getUserData(MUTABLE_CONTENT_LISTENER);
+    if (mc != null) {
+      mc.documentChanged();
     }
   }
 
-  public MutableContent(GadgetHtmlParser contentParser) {
+  /**
+   * NOTE! Passed documents are cloned to ensure they are safe prior to rewriting
+   */
+  public MutableContent(GadgetHtmlParser contentParser, String content, Document document) {
     this.contentParser = contentParser;
-    this.contentParseId = parseEditId = 0;
+    this.content = content;
+    this.document = document;
+    if (document != null) {
+      // There are many shared document instances so cloning is essential
+      // TODO - Consider doing a late clone
+      this.document = (Document) document.cloneNode(true);
+      HtmlSerializer.copySerializer(document, this.document);
+      this.document.setUserData(MUTABLE_CONTENT_LISTENER, this, null);
+    }
+
   }
 
   /**
@@ -59,15 +68,7 @@
    * @return Renderable/active content.
    */
   public String getContent() {
-    if (parseEditId > contentParseId) {
-      // Regenerate content from parse tree node, since the parse tree
-      // was modified relative to the last time content was generated from it.
-      // This is an expensive operation that should happen only once
-      // per rendering cycle: all rewriters (or other manipulators)
-      // operating on the parse tree should happen together.
-      contentParseId = parseEditId;
-
-      // Parser will have bound an HTML serializer to the document
+    if (content == null && document != null) {
       content = HtmlSerializer.serialize(document);
     }
     return content;
@@ -75,103 +76,53 @@
   
   /**
    * Sets the object's content as a raw String. Note, this operation
-   * may be done at any time, even after a parse tree node has been retrieved
-   * and modified (though a warning will be emitted in this case). Once
-   * new content has been set, all subsequent edits to parse trees generated
-   * from the <i>previous</i> content will be invalid, throwing an
-   * {@code IllegalStateException}.
+   * may clears the document if the content has changed
    * @param newContent New content.
    */
   public void setContent(String newContent) {
-    if (content == null ||
-        !content.equals(newContent)) {
+    // TODO - Equality check may be unnecessary overhead
+    if (content == null || !content.equals(newContent)) {
       content = newContent;
-      if (editListener != null) {
-        editListener.stringEdited();
-      }
+      document = null;
     }
   }
 
 
   /**
-   * Sets the object's document. Note, this operation
-   * may be done at any time, even after a parse tree node has been retrieved
-   * and modified (though a warning will be emitted in this case).
-   * @param doc New document.
+   * Notification that the content of the document has changed. Causes the content
+   * string to be cleared
    */
-  public void setDocument(Document doc) {
-    document = doc;
-    if (editListener != null) {
-      editListener.nodeEdited();
-    } else {
-      editListener = new ContentEditListener();
+  public void documentChanged() {
+    if (document != null) {
+      content = null;
     }
   }
   
   /**
-   * Retrieves the object contents in parse tree form, if a
+   * Retrieves the object contents in parsed form, if a
    * {@code GadgetHtmlParser} is configured and is able to parse the string
-   * contents appropriately. The resultant parse tree has a special,
-   * single top-level node that wraps all subsequent content, with
-   * tag name {@code ROOT_NODE_TAG_NAME}. While it may be edited just
-   * as any other node may, doing so is pointless since the root node
-   * is stripped out during rendering. Any edits to the returned parse
-   * tree performed after the source {@code MutableHtmlContent} has new content
-   * set via {@code setContent} will throw an {@code IllegalStateException}
-   * to maintain content consistency in the object. To modify the object's
+   * contents appropriately. To modify the object's
    * contents by parse tree after setting new String contents,
    * this method must be called again. However, this practice is highly
-   * discouraged, as parsing a tree from String is a costly operation.
-   * @return Top-level node whose children represent the gadget's contents, or
-   *         null if no parser is configured, String contents are null, or contents unparseable.
+   * discouraged, as parsing a tree from String is a costly operation and should
+   * be done at most once per rewrite.
    */
   public Document getDocument() {
-    if (document != null && !editListener.stringWasEdited()) {
+    // TODO - Consider actually imposing one parse limit on rewriter pipeline
+    if (document != null) {
       return document;
     }
-  
     if (content == null || contentParser == null) {
       return null;
     }
   
-    // One ContentEditListener per parse tree.
-    editListener = new ContentEditListener();
     try {
       document = contentParser.parseDom(content);
-      if (document != null) {
-        document.setUserData(MUTABLE_CONTENT_LISTENER, editListener, null);
-      }
+      document.setUserData(MUTABLE_CONTENT_LISTENER, this, null);
     } catch (GadgetException e) {
       // TODO: emit info message
       return null;
     }
-  
-    // Parse tree created from content: edit IDs are the same
-    contentParseId = parseEditId;
     return document;
   }
-  
-  // Intermediary object tracking edit behavior for the MutableHtmlContent to help maintain
-  // state consistency. Modifiers of doucments call nodeEdited whenever a modification
-  // is made to its original source.
-  private class ContentEditListener {
-    private boolean stringEdited = false;
-
-    public void nodeEdited() {
-      ++parseEditId;
-      if (stringEdited) {
-        // Parse tree is invalid: a new String representation was set
-        // as tree source in the meantime.
-        throw new IllegalStateException("Edited parse node after setting String content");
-      }
-    }
-
-    private void stringEdited() {
-      stringEdited = true;
-    }
-
-    private boolean stringWasEdited() {
-      return stringEdited;
-    }
-  }
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriterUtils.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriterUtils.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriterUtils.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriterUtils.java Thu Nov  6 23:34:51 2008
@@ -18,41 +18,14 @@
  */
 package org.apache.shindig.gadgets.rewrite;
 
-import com.google.common.collect.Lists;
 import org.apache.shindig.gadgets.http.HttpRequest;
 import org.apache.shindig.gadgets.http.HttpResponse;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.traversal.DocumentTraversal;
-import org.w3c.dom.traversal.NodeFilter;
-import org.w3c.dom.traversal.NodeIterator;
-
-import java.util.List;
-import java.util.Set;
 
 /**
  * Various utility functions used by rewriters
  */
 public class RewriterUtils {
-  public static List<Node> getElementsByTagNameCaseInsensitive(Document doc,
-      final Set<String> lowerCaseNames) {
-    final List<Node> result = Lists.newArrayList();
-    NodeIterator nodeIterator = ((DocumentTraversal) doc)
-        .createNodeIterator(doc, NodeFilter.SHOW_ELEMENT,
-            new NodeFilter() {
-              public short acceptNode(Node n) {
-                if (lowerCaseNames.contains(n.getNodeName().toLowerCase())) {
-                  return NodeFilter.FILTER_ACCEPT;
-                }
-                return NodeFilter.FILTER_REJECT;
-              }
-            }, false);
-    for (Node n = nodeIterator.nextNode(); n != null ; n = nodeIterator.nextNode()) {
-      result.add(n);
-    }
-    return result;
-  }
-
+  
   public static boolean isHtml(HttpRequest request, HttpResponse original) {
     String mimeType = getMimeType(request, original);
     return mimeType != null && (mimeType.contains("html"));

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleLinksContentRewriter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleLinksContentRewriter.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleLinksContentRewriter.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleLinksContentRewriter.java Thu Nov  6 23:34:51 2008
@@ -22,10 +22,10 @@
 import com.google.inject.Inject;
 import com.google.inject.name.Named;
 import org.apache.shindig.common.uri.Uri;
-import org.apache.shindig.common.xml.XmlUtil;
 import org.apache.shindig.gadgets.Gadget;
 import org.apache.shindig.gadgets.http.HttpRequest;
 import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.parse.DomUtil;
 import org.apache.shindig.gadgets.spec.View;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
@@ -89,20 +89,15 @@
     }
     boolean mutated = false;
 
-    // TODO This should move into parsers
-    Node head = XmlUtil.getFirstNamedChildNode(doc.getDocumentElement(), "head");
-    if (head == null) {
-      mutated = true;
-      head = doc.getDocumentElement().appendChild(doc.createElement("head"));
-    }
+    Node head = DomUtil.getFirstNamedChildNode(doc.getDocumentElement(), "head");
 
     // Move all style tags into head
     // TODO Convert all @imports into a concatenated link tag
-    List<Node> styleTags = RewriterUtils.getElementsByTagNameCaseInsensitive(doc,
+    List<Node> styleTags = DomUtil.getElementsByTagNameCaseInsensitive(doc,
         Sets.newHashSet("style"));
     for (Node styleNode : styleTags) {      
       mutated = true;
-      if (!styleNode.getParentNode().getNodeName().equalsIgnoreCase("HEAD")) {
+      if (styleNode.getParentNode() != head) {
         styleNode.getParentNode().removeChild(styleNode);
         head.appendChild(styleNode);
       }

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/HtmlParserTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/HtmlParserTest.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/HtmlParserTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/HtmlParserTest.java Thu Nov  6 23:34:51 2008
@@ -44,7 +44,7 @@
   private void parseSimpleString(GadgetHtmlParser htmlParser) throws Exception {
     Document doc = htmlParser.parseDom("content");
 
-    Node node = doc.getDocumentElement().getFirstChild();
+    Node node = doc.getDocumentElement().getFirstChild().getNextSibling();
     assertNotNull(node);
     assertEquals("content", node.getTextContent());
     assertNull(node.getAttributes());
@@ -60,7 +60,7 @@
   void parseTagWithStringContents(GadgetHtmlParser htmlParser) throws Exception {
     Document doc = htmlParser.parseDom("<span>content</span>");
 
-    Node node = doc.getDocumentElement().getFirstChild();
+    Node node = doc.getDocumentElement().getFirstChild().getNextSibling();
     assertEquals("content", node.getTextContent());
     assertEquals("span", node.getNodeName().toLowerCase());
   }
@@ -73,7 +73,7 @@
   void parseTagWithAttributes(GadgetHtmlParser htmlParser) throws Exception {
     Document doc = htmlParser.parseDom("<div id=\"foo\">content</div>");
 
-    Node node = doc.getDocumentElement().getFirstChild();
+    Node node = doc.getDocumentElement().getFirstChild().getNextSibling();
     assertNotNull(node);
     assertNotNull(node.getAttributes());
     assertEquals(1, node.getAttributes().getLength());
@@ -92,7 +92,7 @@
   void parseStringUnescapesProperly(GadgetHtmlParser htmlParser) throws Exception {
     Document doc = htmlParser.parseDom("&lt;content&amp;&apos;chrome&apos;&gt;");
 
-    Node node = doc.getDocumentElement().getFirstChild();
+    Node node = doc.getDocumentElement().getFirstChild().getNextSibling();
     assertNotNull(node);
     assertEquals("<content&'chrome'>", node.getTextContent());
     assertNull(node.getAttributes());
@@ -107,7 +107,7 @@
   void parseNestedContentWithNoCloseForBrAndHr(GadgetHtmlParser htmlParser) throws Exception {
     Document doc = htmlParser.parseDom("<div><br>  and  <hr></div>");
 
-    Node divNode = doc.getDocumentElement().getFirstChild();
+    Node divNode = doc.getDocumentElement().getFirstChild().getNextSibling();
     assertEquals("div", divNode.getNodeName().toLowerCase());
     assertNotNull(divNode.getAttributes());
     assertEquals(0, divNode.getAttributes().getLength());

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/nekohtml/NekoSimplifiedHtmlParserTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/nekohtml/NekoSimplifiedHtmlParserTest.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/nekohtml/NekoSimplifiedHtmlParserTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/nekohtml/NekoSimplifiedHtmlParserTest.java Thu Nov  6 23:34:51 2008
@@ -33,27 +33,27 @@
 
   public void testUnbalanced() throws Exception {
     parseAndCompareBalanced("<html><body><center>content</body></html>",
-        "<html><body><center>content</body></html>");
+        "<html><head></head><body><center>content</body></html>");
   }
 
   public void testUnbalanced2() throws Exception {
     parseAndCompareBalanced("<html><body><img>content<img>content</body></html>",
-        "<HTML><body><IMG>content<IMG>content</body></HTML>");
+        "<HTML><head></head><body><IMG>content<IMG>content</body></HTML>");
   }
 
   public void testUnbalanced3() throws Exception {
     parseAndCompareBalanced("<html><body><select><option>content<option></body></html>",
-        "<html><body><select><option>content<option></body></html>");
+        "<html><head></head><body><select><option>content<option></body></html>");
   }
 
   public void testUnbalanced4() throws Exception {
     parseAndCompareBalanced("<html><body>Something awful</html>",
-        "<HTML><body>Something awful</body></HTML>");
+        "<HTML><head></head><body>Something awful</body></HTML>");
   }
 
   public void testUnbalanced5() throws Exception {
     parseAndCompareBalanced("<html><body><br />content<br></html>",
-        "<HTML><body><br />content<br></body></HTML>");
+        "<HTML><head></head><body><br />content<br></body></HTML>");
   }
 
   private void parseAndCompareBalanced(String content, String expected) throws Exception {

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/HtmlRendererTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/HtmlRendererTest.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/HtmlRendererTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/HtmlRendererTest.java Thu Nov  6 23:34:51 2008
@@ -18,9 +18,7 @@
  */
 package org.apache.shindig.gadgets.render;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
+import com.google.common.collect.Maps;
 import org.apache.shindig.auth.AnonymousSecurityToken;
 import org.apache.shindig.auth.SecurityToken;
 import org.apache.shindig.common.uri.Uri;
@@ -37,9 +35,8 @@
 import org.apache.shindig.gadgets.rewrite.ContentRewriterRegistry;
 import org.apache.shindig.gadgets.spec.GadgetSpec;
 import org.apache.shindig.gadgets.spec.View;
-
-import com.google.common.collect.Maps;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import org.junit.Test;
 
 import java.util.Arrays;
@@ -214,6 +211,10 @@
   private static class FakeContentRewriterRegistry implements ContentRewriterRegistry {
     private boolean wasRewritten = false;
 
+    public String rewriteGadget(Gadget gadget, View currentView) throws GadgetException {
+      throw new UnsupportedOperationException();
+    }
+
     public String rewriteGadget(Gadget gadget, String content) {
       wasRewritten = true;
       return content;

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingContentRewriterTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingContentRewriterTest.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingContentRewriterTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingContentRewriterTest.java Thu Nov  6 23:34:51 2008
@@ -18,59 +18,34 @@
  */
 package org.apache.shindig.gadgets.render;
 
-import static org.apache.shindig.gadgets.render.RenderingContentRewriter.BEFORE_HEAD_GROUP;
-import static org.apache.shindig.gadgets.render.RenderingContentRewriter.BODY_ATTRIBUTES_GROUP;
-import static org.apache.shindig.gadgets.render.RenderingContentRewriter.BODY_GROUP;
-import static org.apache.shindig.gadgets.render.RenderingContentRewriter.DEFAULT_HEAD_CONTENT;
-import static org.apache.shindig.gadgets.render.RenderingContentRewriter.DOCUMENT_SPLIT_PATTERN;
-import static org.apache.shindig.gadgets.render.RenderingContentRewriter.FEATURES_KEY;
-import static org.apache.shindig.gadgets.render.RenderingContentRewriter.HEAD_GROUP;
-import static org.apache.shindig.gadgets.render.RenderingContentRewriter.INSERT_BASE_ELEMENT_KEY;
-import static org.easymock.EasyMock.expect;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
+import com.google.caja.util.Join;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import org.apache.shindig.common.ContainerConfig;
 import org.apache.shindig.common.uri.Uri;
 import org.apache.shindig.common.xml.XmlUtil;
-import org.apache.shindig.gadgets.Gadget;
-import org.apache.shindig.gadgets.GadgetContext;
-import org.apache.shindig.gadgets.GadgetException;
-import org.apache.shindig.gadgets.GadgetFeature;
-import org.apache.shindig.gadgets.GadgetFeatureRegistry;
-import org.apache.shindig.gadgets.JsLibrary;
-import org.apache.shindig.gadgets.MessageBundleFactory;
-import org.apache.shindig.gadgets.UrlGenerator;
+import org.apache.shindig.gadgets.*;
 import org.apache.shindig.gadgets.preload.NullPreloads;
 import org.apache.shindig.gadgets.preload.PreloadException;
 import org.apache.shindig.gadgets.preload.PreloadedData;
 import org.apache.shindig.gadgets.preload.Preloads;
+import static org.apache.shindig.gadgets.render.RenderingContentRewriter.*;
 import org.apache.shindig.gadgets.rewrite.MutableContent;
 import org.apache.shindig.gadgets.spec.GadgetSpec;
 import org.apache.shindig.gadgets.spec.LocaleSpec;
 import org.apache.shindig.gadgets.spec.MessageBundle;
 import org.apache.shindig.gadgets.spec.View;
-
-import com.google.caja.util.Join;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
+import static org.easymock.EasyMock.expect;
 import org.easymock.classextension.EasyMock;
 import org.easymock.classextension.IMocksControl;
 import org.json.JSONException;
 import org.json.JSONObject;
+import static org.junit.Assert.*;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -109,8 +84,7 @@
   }
 
   private String rewrite(Gadget gadget, String content) {
-    MutableContent mc = new MutableContent(null);
-    mc.setContent(content);
+    MutableContent mc = new MutableContent(null, content, null);
     assertEquals(0, rewriter.rewrite(gadget, mc).getCacheTtl());
     return mc.getContent();
   }

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/BaseRewriterTestCase.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/BaseRewriterTestCase.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/BaseRewriterTestCase.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/BaseRewriterTestCase.java Thu Nov  6 23:34:51 2008
@@ -108,8 +108,7 @@
 
   MutableContent rewriteContent(ContentRewriter rewriter, String s)
       throws Exception {
-    MutableContent mc = new MutableContent(parser);
-    mc.setContent(s);
+    MutableContent mc = new MutableContent(parser, s, null);
 
     GadgetSpec spec = new GadgetSpec(SPEC_URL,
         "<Module><ModulePrefs title=''/><Content><![CDATA[" + s + "]]></Content></Module>");

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/DefaultContentRewriterRegistryTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/DefaultContentRewriterRegistryTest.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/DefaultContentRewriterRegistryTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/DefaultContentRewriterRegistryTest.java Thu Nov  6 23:34:51 2008
@@ -17,34 +17,38 @@
  */
 package org.apache.shindig.gadgets.rewrite;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
+import com.google.common.collect.Lists;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import junit.framework.TestCase;
 import org.apache.shindig.common.uri.Uri;
 import org.apache.shindig.gadgets.Gadget;
 import org.apache.shindig.gadgets.GadgetContext;
 import org.apache.shindig.gadgets.http.HttpRequest;
 import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.parse.GadgetHtmlParser;
+import org.apache.shindig.gadgets.parse.ParseModule;
 import org.apache.shindig.gadgets.spec.GadgetSpec;
 
-import com.google.common.collect.Lists;
-
-import org.junit.Test;
-
 import java.util.Arrays;
 import java.util.List;
 
-public class DefaultContentRewriterRegistryTest {
+public class DefaultContentRewriterRegistryTest extends TestCase {
   private static final Uri SPEC_URL = Uri.parse("http://example.org/gadget.xml");
-  private final List<CaptureRewriter> rewriters
-      = Arrays.asList(new CaptureRewriter(), new CaptureRewriter());
-  private final List<ContentRewriter> contentRewriters
-      = Lists.<ContentRewriter>newArrayList(rewriters);
-  private final ContentRewriterRegistry registry
-      = new DefaultContentRewriterRegistry(contentRewriters, null);
+  private List<CaptureRewriter> rewriters;
+  private List<ContentRewriter> contentRewriters;
+  private ContentRewriterRegistry registry;
+  private GadgetHtmlParser parser;
+
+  protected void setUp() throws Exception {
+    Injector injector = Guice.createInjector(new ParseModule());
+    parser = injector.getInstance(GadgetHtmlParser.class);
+    rewriters = Arrays.asList(new CaptureRewriter(), new CaptureRewriter());
+    contentRewriters = Lists.<ContentRewriter>newArrayList(rewriters);
+    registry = new DefaultContentRewriterRegistry(contentRewriters, parser);
+  }
 
-  @Test
-  public void rewriteGadget() throws Exception {
+  public void testRewriteGadget() throws Exception {
     String body = "Hello, world";
     String xml = "<Module><ModulePrefs title=''/><Content>" + body + "</Content></Module>";
     GadgetSpec spec = new GadgetSpec(SPEC_URL, xml);
@@ -61,8 +65,7 @@
     assertEquals(body, rewritten);
   }
 
-  @Test
-  public void rewriteHttpResponse() throws Exception {
+  public void testRewriteHttpResponse() throws Exception {
     String body = "Hello, world";
     HttpRequest request = new HttpRequest(SPEC_URL);
     HttpResponse response = new HttpResponse(body);
@@ -74,4 +77,21 @@
 
     assertEquals(response, rewritten);
   }
+
+  public void testRewriteView() throws Exception {
+    String body = "Hello, world";
+    String xml = "<Module><ModulePrefs title=''/><Content>" + body + "</Content></Module>";
+    GadgetSpec spec = new GadgetSpec(SPEC_URL, xml);
+    GadgetContext context = new GadgetContext();
+    Gadget gadget = new Gadget()
+        .setContext(context)
+        .setSpec(spec);
+
+    String rewritten = registry.rewriteGadget(gadget, spec.getView("default"));
+
+    assertTrue("First rewriter invoked.", rewriters.get(0).viewWasRewritten());
+    assertTrue("Second rewriter invoked.", rewriters.get(1).viewWasRewritten());
+
+    assertEquals(body, rewritten); 
+  }
 }

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/JsTagConcatContentRewriterTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/JsTagConcatContentRewriterTest.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/JsTagConcatContentRewriterTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/JsTagConcatContentRewriterTest.java Thu Nov  6 23:34:51 2008
@@ -55,7 +55,7 @@
 
   public void testJSMergeSingleScriptReWrite() throws Exception {
     String s = "<script src=\"http://a.b.com/1.js\"></script>";
-    String expected = "<script src=\"" + concatBase + "1=http%3A%2F%2Fa.b.com%2F1.js\"></script>";
+    String expected = "<head></head><script src=\"" + concatBase + "1=http%3A%2F%2Fa.b.com%2F1.js\"></script>";
     String rewritten = rewriteHelper(rewriter, s);
     assertEquals(rewritten, expected);
   }
@@ -64,7 +64,7 @@
     String s = "<script src=\"http://a.b.com/1.js\"></script>"
         + "<script src=\"http://a.b.com/2.js\"></script>";
     String expected
-        = "<script src=\"" + concatBase + "1=http%3A%2F%2Fa.b.com%2F1.js&2=http%3A%2F%2Fa.b.com%2F2.js\"></script>";
+        = "<head></head><script src=\"" + concatBase + "1=http%3A%2F%2Fa.b.com%2F1.js&2=http%3A%2F%2Fa.b.com%2F2.js\"></script>";
     String rewritten = rewriteHelper(rewriter, s);
     assertEquals(rewritten, expected);
   }
@@ -78,7 +78,7 @@
         + "<script>\n"
         + "doSomething\n"
         + "</script>";
-    String expected = "<script>\n"
+    String expected = "<head></head><script>\n"
         + "doSomething\n"
         + "</script>"
         + "<script src=\"" + concatBase + "1=http%3A%2F%2Fa.b.com%2F1.js&2=http%3A%2F%2Fa.b.com%2F2.js\"></script>"
@@ -96,7 +96,7 @@
         + "<script src=\"http://a.b.com/3.js\"></script>"
         + "<script src=\"http://a.b.com/4.js\"></script>";
     String expected =
-        "<script src=\"" + concatBase + "1=http%3A%2F%2Fa.b.com%2F1.js&2=http%3A%2F%2Fa.b.com%2F2.js\"></script>" +
+        "<head></head><script src=\"" + concatBase + "1=http%3A%2F%2Fa.b.com%2F1.js&2=http%3A%2F%2Fa.b.com%2F2.js\"></script>" +
         "<script><!-- doSomething --></script>" +
         "<script src=\"" + concatBase + "1=http%3A%2F%2Fa.b.com%2F3.js&2=http%3A%2F%2Fa.b.com%2F4.js\"></script>";
     String rewritten = rewriteHelper(rewriter, s);
@@ -106,7 +106,7 @@
   public void testJSMergeDerelativizeHostRelative() throws Exception {
     String s = "<script src=\"/1.js\"></script>";
     String expected
-        = "<script src=\"" + concatBase + "1=http%3A%2F%2Fexample.org%2F1.js\"></script>";
+        = "<head></head><script src=\"" + concatBase + "1=http%3A%2F%2Fexample.org%2F1.js\"></script>";
     String rewritten = rewriteHelper(rewriter, s);
     assertEquals(rewritten, expected);
   }
@@ -114,7 +114,7 @@
   public void testJSMergeDerelativizePathRelative() throws Exception {
     String s = "<script src=\"1.js\"></script>";
     String expected
-        = "<script src=\"" + concatBase + "1=http%3A%2F%2Fexample.org%2Fdir%2F1.js\"></script>";
+        = "<head></head><script src=\"" + concatBase + "1=http%3A%2F%2Fexample.org%2Fdir%2F1.js\"></script>";
     String rewritten = rewriteHelper(rewriter, s);
     assertEquals(rewritten, expected);
   }

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/LexerVsDomRewriteBenchmark.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/LexerVsDomRewriteBenchmark.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/LexerVsDomRewriteBenchmark.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/LexerVsDomRewriteBenchmark.java Thu Nov  6 23:34:51 2008
@@ -139,8 +139,7 @@
   private void runLexer() throws Exception {
    long startTime = System.currentTimeMillis();
     for (int i = 0; i < numRuns; i++) {
-      MutableContent mc = new MutableContent(null);
-      mc.setContent(content);
+      MutableContent mc = new MutableContent(null, content, null);
       lexerRewriter.rewrite(gadget, mc);
       mc.getContent();
     }
@@ -152,8 +151,7 @@
   private void run(GadgetHtmlParser parser) throws Exception {
     long startTime = System.currentTimeMillis();
     for (int i = 0; i < numRuns; i++) {
-      MutableContent mc = new MutableContent(parser);
-      mc.setContent(content);
+      MutableContent mc = new MutableContent(parser, content, null);
       linkRewriter.rewrite(gadget, mc);
       jsConcatRewriter.rewrite(gadget, mc);
       styleLinksRewriter.rewrite(gadget, mc);
@@ -169,8 +167,7 @@
     Document doc = parser.parseDom(content);
     long startTime = System.currentTimeMillis();
     for (int i = 0; i < numRuns; i++) {
-      MutableContent mc = new MutableContent(parser);
-      mc.setDocument((Document)doc.cloneNode(true));
+      MutableContent mc = new MutableContent(parser, null, doc);
       linkRewriter.rewrite(gadget, mc);
       jsConcatRewriter.rewrite(gadget, mc);
       styleLinksRewriter.rewrite(gadget, mc);

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/LinkingTagContentRewriterTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/LinkingTagContentRewriterTest.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/LinkingTagContentRewriterTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/LinkingTagContentRewriterTest.java Thu Nov  6 23:34:51 2008
@@ -46,7 +46,7 @@
         + "<IMG src=\"http://a.b.com/img2.gif\"/>"
         + "<eMbeD src=\"http://a.b.com/some.mov\"/>"
         + "<link href=\"http://a.b.com/link.html\"></link>";
-    String expected = "<img src=\"" + LINK_PREFIX + "http://a.b.com/img.gif\">"
+    String expected = "<head></head><img src=\"" + LINK_PREFIX + "http://a.b.com/img.gif\">"
         + "<img src=\"" + LINK_PREFIX + "http://a.b.com/img2.gif\">"
         + "<embed src=\"" + LINK_PREFIX + "http://a.b.com/some.mov\"></embed>"
         + "<link href=\"" + LINK_PREFIX + "http://a.b.com/link.html\">";

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/MutableContentTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/MutableContentTest.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/MutableContentTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/MutableContentTest.java Thu Nov  6 23:34:51 2008
@@ -37,8 +37,7 @@
     // sufficient given that this test doesn't exercise the parser extensively at all,
     // instead focusing on the additional utility provided by MutableHtmlContent
     Injector injector = Guice.createInjector(new ParseModule());
-    mhc = new MutableContent(injector.getInstance(GadgetHtmlParser.class));
-    mhc.setContent("DEFAULT VIEW");
+    mhc = new MutableContent(injector.getInstance(GadgetHtmlParser.class), "DEFAULT VIEW", null);
   }
   
   @Test
@@ -47,9 +46,9 @@
     assertEquals("DEFAULT VIEW", content);
   
     Document document = mhc.getDocument();
-    assertEquals(1, document.getFirstChild().getChildNodes().getLength());
-    assertTrue(document.getFirstChild().getChildNodes().item(0).getNodeType() == Node.TEXT_NODE);
-    assertEquals(content, document.getFirstChild().getChildNodes().item(0).getTextContent());
+    assertEquals(2, document.getFirstChild().getChildNodes().getLength());
+    assertTrue(document.getFirstChild().getChildNodes().item(1).getNodeType() == Node.TEXT_NODE);
+    assertEquals(content, document.getFirstChild().getChildNodes().item(1).getTextContent());
   
     assertSame(content, mhc.getContent());
     assertSame(document, mhc.getDocument());
@@ -80,35 +79,4 @@
     // GadgetHtmlNode hasn't changed because string hasn't changed
     assertSame(document, mhc.getDocument());
   }
-  
-  @Test
-  public void staleTreeEditsInvalidatedAfterContentSet() throws Exception {
-    Document document = mhc.getDocument();
-  
-    // Re-set content
-    mhc.setContent("INVALIDATING CONTENT");
-  
-    // Should still be able to obtain this.
-    Document document2 = mhc.getDocument();
-    assertNotSame(document, document2);
-  
-    // Should be able to *obtain* first child node...
-    Node firstTextNode = document.getFirstChild().getChildNodes().item(0);
-    try {
-      // ...but not edit it.
-      firstTextNode.setTextContent("STALE-SET CONTENT");
-      MutableContent.notifyEdit(document);
-      fail("Should not be able to modify stale parse tree");
-    } catch (IllegalStateException e) {
-      // Expected condition.
-    }
-  
-    assertEquals("INVALIDATING CONTENT",
-        document2.getFirstChild().getChildNodes().item(0).getTextContent());
-  
-    // For good measure, modify secondRoot and get content
-    document2.getFirstChild().getChildNodes().item(0).setTextContent("NEW CONTENT");
-    MutableContent.notifyEdit(document2);
-    assertTrue(mhc.getContent().contains("NEW CONTENT"));
-  }
 }

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleLinksContentRewriterTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleLinksContentRewriterTest.java?rev=712080&r1=712079&r2=712080&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleLinksContentRewriterTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleLinksContentRewriterTest.java Thu Nov  6 23:34:51 2008
@@ -19,6 +19,7 @@
 package org.apache.shindig.gadgets.rewrite;
 
 import com.google.common.collect.Sets;
+import org.apache.shindig.gadgets.parse.DomUtil;
 
 import java.net.URI;
 
@@ -54,7 +55,7 @@
     // Rewrite, document is mutated in-place
     MutableContent content = rewriteContent(rewriter, s);
     assertEquals(rewritten,
-        RewriterUtils.getElementsByTagNameCaseInsensitive(content.getDocument(),
+        DomUtil.getElementsByTagNameCaseInsensitive(content.getDocument(),
             Sets.newHashSet("style")).get(0).getTextContent());
   }