You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by jo...@apache.org on 2010/03/09 02:39:20 UTC

svn commit: r920612 - in /shindig/trunk/java/gadgets/src: main/java/org/apache/shindig/gadgets/rewrite/ test/java/org/apache/shindig/gadgets/rewrite/

Author: johnh
Date: Tue Mar  9 01:39:19 2010
New Revision: 920612

URL: http://svn.apache.org/viewvc?rev=920612&view=rev
Log:
Implements operation that pulls out @imports from CSS and turns them into external references in the proper order. Logic separated from HTMLContentRewriter. Not activated in any current code path as of this CL.


Added:
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorContentRewriter.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorVisitor.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorContentRewriterTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorVisitorTest.java

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorContentRewriter.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorContentRewriter.java?rev=920612&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorContentRewriter.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorContentRewriter.java Tue Mar  9 01:39:19 2010
@@ -0,0 +1,53 @@
+/*
+ * 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.rewrite;
+
+import com.google.inject.Inject;
+
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.Gadget;
+import org.apache.shindig.gadgets.rewrite.DomWalker;
+import org.apache.shindig.gadgets.rewrite.DomWalker.Visitor;
+import org.apache.shindig.gadgets.uri.ConcatUriManager;
+import org.apache.shindig.gadgets.uri.ProxyUriManager;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class StyleTagExtractorContentRewriter extends DomWalker.Rewriter {
+  private final ContentRewriterFeature.Factory featureConfigFactory;
+  private final ProxyUriManager proxyUriManager;
+  private final CssRequestRewriter cssRewriter;
+  
+  @Inject
+  public StyleTagExtractorContentRewriter(ContentRewriterFeature.Factory featureConfigFactory,
+      ConcatUriManager concatUriManager, ProxyUriManager proxyUriManager,
+      CssRequestRewriter cssRewriter) {
+    this.featureConfigFactory = featureConfigFactory;
+    this.proxyUriManager = proxyUriManager;
+    this.cssRewriter = cssRewriter;
+  }
+  
+  @Override
+  protected List<Visitor> makeVisitors(Gadget context, Uri gadgetUri) {
+    ContentRewriterFeature.Config config = featureConfigFactory.get(gadgetUri);
+    return Arrays.<Visitor>asList(
+        new StyleTagExtractorVisitor(config, cssRewriter, proxyUriManager));
+  }
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorVisitor.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorVisitor.java?rev=920612&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorVisitor.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorVisitor.java Tue Mar  9 01:39:19 2010
@@ -0,0 +1,92 @@
+/*
+ * 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.rewrite;
+
+import java.util.List;
+
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.common.xml.DomUtil;
+import org.apache.shindig.gadgets.Gadget;
+import org.apache.shindig.gadgets.rewrite.DomWalker.Visitor;
+import org.apache.shindig.gadgets.spec.View;
+import org.apache.shindig.gadgets.uri.ProxyUriManager;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+public class StyleTagExtractorVisitor implements Visitor {
+  private final ContentRewriterFeature.Config config;
+  private final CssRequestRewriter cssRewriter;
+  private final ProxyUriManager proxyUriManager;
+  
+  public StyleTagExtractorVisitor(ContentRewriterFeature.Config config,
+      CssRequestRewriter cssRewriter, ProxyUriManager proxyUriManager) {
+    this.config = config;
+    this.cssRewriter = cssRewriter;
+    this.proxyUriManager = proxyUriManager;
+  }
+
+  public VisitStatus visit(Gadget gadget, Node node) throws RewritingException {
+    if (!config.isRewriteEnabled() || !config.getIncludedTags().contains("style")) {
+      return VisitStatus.BYPASS;
+    }
+    
+    // Only process <style> elements.
+    if (node.getNodeType() != Node.ELEMENT_NODE ||
+        !node.getNodeName().equalsIgnoreCase("style")) {
+      return VisitStatus.BYPASS;
+    }
+    
+    return VisitStatus.RESERVE_NODE;
+  }
+
+  public boolean revisit(Gadget gadget, List<Node> nodes)
+      throws RewritingException {
+    boolean mutated = false;
+    if (nodes.size() == 0) {
+      return mutated;
+    }
+    
+    Uri contentBase = gadget.getSpec().getUrl();
+    View view = gadget.getCurrentView();
+    if (view != null && view.getHref() != null) {
+      contentBase = view.getHref();
+    }
+    
+    Element head = (Element)DomUtil.getFirstNamedChildNode(
+        nodes.get(0).getOwnerDocument().getDocumentElement(), "head");
+    for (Node node : nodes) {
+      // Guaranteed safe cast due to reservation logic.
+      Element elem = (Element)node;
+      List<String> extractedUrls = cssRewriter.rewrite(
+          elem, contentBase, CssRequestRewriter.uriMaker(proxyUriManager, config), true);
+      for (String extractedUrl : extractedUrls) {
+        // Add extracted urls as link elements to head
+        Element newLink = head.getOwnerDocument().createElement("link");
+        newLink.setAttribute("rel", "stylesheet");
+        newLink.setAttribute("type", "text/css");
+        newLink.setAttribute("href", extractedUrl);
+        head.appendChild(newLink);
+        mutated = true;
+      }
+    }
+    
+    return mutated;
+  }
+
+}

Added: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorContentRewriterTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorContentRewriterTest.java?rev=920612&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorContentRewriterTest.java (added)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorContentRewriterTest.java Tue Mar  9 01:39:19 2010
@@ -0,0 +1,28 @@
+/*
+ * 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.rewrite;
+
+import org.junit.Test;
+
+public class StyleTagExtractorContentRewriterTest {
+  @Test
+  public void implementIntegrationTests() throws Exception {
+    // TODO: what the method says
+  }
+}

Added: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorVisitorTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorVisitorTest.java?rev=920612&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorVisitorTest.java (added)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleTagExtractorVisitorTest.java Tue Mar  9 01:39:19 2010
@@ -0,0 +1,255 @@
+/*
+ * 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.rewrite;
+
+import static org.easymock.classextension.EasyMock.createMock;
+import static org.easymock.classextension.EasyMock.eq;
+import static org.easymock.classextension.EasyMock.expect;
+import static org.easymock.classextension.EasyMock.isA;
+import static org.easymock.classextension.EasyMock.replay;
+import static org.easymock.classextension.EasyMock.verify;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.ImmutableList;
+import com.google.inject.internal.ImmutableSet;
+
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.Gadget;
+import org.apache.shindig.gadgets.rewrite.CssRequestRewriter.UriMaker;
+import org.apache.shindig.gadgets.rewrite.DomWalker.Visitor.VisitStatus;
+import org.apache.shindig.gadgets.uri.PassthruManager;
+import org.apache.shindig.gadgets.uri.ProxyUriManager;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.w3c.dom.Comment;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+import java.util.List;
+
+public class StyleTagExtractorVisitorTest extends DomWalkerTestBase {
+  private ProxyUriManager proxyUriManager;
+  
+  @Before
+  public void setUp() {
+    super.setUp();
+    proxyUriManager = new PassthruManager();
+  }
+  
+  @Test
+  public void visitBypassesComment() throws Exception {
+    Comment comment = doc.createComment("comment");
+    assertEquals(VisitStatus.BYPASS, getVisitStatus(comment));
+  }
+  
+  @Test
+  public void visitBypassesText() throws Exception {
+    Text text = doc.createTextNode("text");
+    assertEquals(VisitStatus.BYPASS, getVisitStatus(text));
+  }
+  
+  @Test
+  public void visitBypassesNonStyle() throws Exception {
+    Node node = elem("div");
+    assertEquals(VisitStatus.BYPASS, getVisitStatus(node));
+  }
+  
+  @Test
+  public void visitBypassesStyleWhenRewriterOff() throws Exception {
+    assertEquals(VisitStatus.BYPASS, getVisitStatus(config(false, true, true), elem("style")));
+  }
+  
+  @Test
+  public void visitBypassesStyleWhenStyleTagNotIncluded() throws Exception {
+    assertEquals(VisitStatus.BYPASS, getVisitStatus(config(true, false, true), elem("style")));
+  }
+  
+  @Test
+  public void visitReservesStyleNode() throws Exception {
+    assertEquals(VisitStatus.RESERVE_NODE, getVisitStatus(elem("style")));
+  }
+  
+  @Test
+  public void visitReservesCasedStyleNode() throws Exception {
+    assertEquals(VisitStatus.RESERVE_NODE, getVisitStatus(elem("sTyLE")));
+  }
+  
+  @Test
+  public void revisitNothingExtracted() throws Exception {
+    Gadget gadget = gadget();
+    CssRequestRewriter cssRewriter = createMock(CssRequestRewriter.class);
+    replay(cssRewriter);
+    
+    // Tag name isn't inspected since visit() filters this.
+    List<Node> nodes = ImmutableList.<Node>of();
+    Node head = addNodesToHtml(nodes);
+    
+    assertFalse(getRevisitStatus(gadget, true, cssRewriter, nodes));
+    verify(cssRewriter);
+    assertEquals(0, head.getChildNodes().getLength());
+  }
+  
+  @Test
+  public void revisitExtractSpecRelative() throws Exception {
+    Uri base = GADGET_URI;
+    Gadget gadget = gadget();
+    CssRequestRewriter cssRewriter = createMock(CssRequestRewriter.class);
+    Element elem1 = elem("elem1");
+    Element elem2 = elem("elem2");
+    String urlStr1 = "http://foo.com/1.css";
+    List<String> extractedUrls1 = ImmutableList.of(urlStr1);
+    String urlStr2 = "http://bar.com/1.css";
+    List<String> extractedUrls2 = ImmutableList.of(urlStr2);
+    expect(cssRewriter.rewrite(eq(elem1), eq(base), isA(UriMaker.class), eq(true)))
+        .andReturn(extractedUrls1).once();
+    expect(cssRewriter.rewrite(eq(elem2), eq(base), isA(UriMaker.class), eq(true)))
+        .andReturn(extractedUrls2).once();
+    replay(cssRewriter);
+    
+    // Tag name isn't inspected since visit() filters this.
+    List<Node> nodes = ImmutableList.<Node>of(elem1, elem2);
+    Node head = addNodesToHtml(nodes);
+    
+    assertTrue(getRevisitStatus(gadget, true, cssRewriter, nodes));
+    verify(cssRewriter);
+    assertEquals(2, head.getChildNodes().getLength());
+    Element child1 = (Element)head.getChildNodes().item(0);
+    assertEquals("link", child1.getTagName());
+    assertEquals("stylesheet", child1.getAttribute("rel"));
+    assertEquals("text/css", child1.getAttribute("type"));
+    // PassthruManager doesn't modify the inbound URI.
+    assertEquals(urlStr1, child1.getAttribute("href"));
+    Element child2 = (Element)head.getChildNodes().item(1);
+    assertEquals("link", child2.getTagName());
+    assertEquals("stylesheet", child2.getAttribute("rel"));
+    assertEquals("text/css", child2.getAttribute("type"));
+    // PassthruManager doesn't modify the inbound URI.
+    assertEquals(urlStr2, child2.getAttribute("href"));
+  }
+  
+  @Test
+  public void revisitExtractViewHrefRelative() throws Exception {
+    Uri base = Uri.parse("http://view.com/viewbase.xml");
+    Gadget gadget = gadget(true, true, base);
+    CssRequestRewriter cssRewriter = createMock(CssRequestRewriter.class);
+    Element elem1 = elem("elem1");
+    Element elem2 = elem("elem2");
+    String urlStr1 = "http://foo.com/1.css";
+    List<String> extractedUrls1 = ImmutableList.of(urlStr1);
+    String urlStr2 = "http://bar.com/1.css";
+    List<String> extractedUrls2 = ImmutableList.of(urlStr2);
+    expect(cssRewriter.rewrite(eq(elem1), eq(base), isA(UriMaker.class), eq(true)))
+        .andReturn(extractedUrls1).once();
+    expect(cssRewriter.rewrite(eq(elem2), eq(base), isA(UriMaker.class), eq(true)))
+        .andReturn(extractedUrls2).once();
+    replay(cssRewriter);
+    
+    // Tag name isn't inspected since visit() filters this.
+    List<Node> nodes = ImmutableList.<Node>of(elem1, elem2);
+    Node head = addNodesToHtml(nodes);
+    
+    assertTrue(getRevisitStatus(gadget, true, cssRewriter, nodes));
+    verify(cssRewriter);
+    assertEquals(2, head.getChildNodes().getLength());
+    Element child1 = (Element)head.getChildNodes().item(0);
+    assertEquals("link", child1.getTagName());
+    assertEquals("stylesheet", child1.getAttribute("rel"));
+    assertEquals("text/css", child1.getAttribute("type"));
+    // PassthruManager doesn't modify the inbound URI.
+    assertEquals(urlStr1, child1.getAttribute("href"));
+    Element child2 = (Element)head.getChildNodes().item(1);
+    assertEquals("link", child2.getTagName());
+    assertEquals("stylesheet", child2.getAttribute("rel"));
+    assertEquals("text/css", child2.getAttribute("type"));
+    // PassthruManager doesn't modify the inbound URI.
+    assertEquals(urlStr2, child2.getAttribute("href"));
+  }
+  
+  @Test
+  public void revisitExtractSpecRelativeDisabled() throws Exception {
+    Uri base = GADGET_URI;
+    Gadget gadget = gadget();
+    CssRequestRewriter cssRewriter = createMock(CssRequestRewriter.class);
+    Element elem1 = elem("elem1");
+    Element elem2 = elem("elem2");
+    List<String> extractedUrls1 = ImmutableList.of();
+    List<String> extractedUrls2 = ImmutableList.of();
+    expect(cssRewriter.rewrite(eq(elem1), eq(base), isA(UriMaker.class), eq(true)))
+        .andReturn(extractedUrls1).once();
+    expect(cssRewriter.rewrite(eq(elem2), eq(base), isA(UriMaker.class), eq(true)))
+        .andReturn(extractedUrls2).once();
+    replay(cssRewriter);
+    
+    // Tag name isn't inspected since visit() filters this.
+    List<Node> nodes = ImmutableList.<Node>of(elem1, elem2);
+    Node head = addNodesToHtml(nodes);
+    
+    assertFalse(getRevisitStatus(gadget, false, cssRewriter, nodes));
+    verify(cssRewriter);
+    assertEquals(0, head.getChildNodes().getLength());
+  }
+  
+  private VisitStatus getVisitStatus(Node node) throws Exception {
+    return getVisitStatus(config(true, true, true), node);
+  }
+
+  private VisitStatus getVisitStatus(ContentRewriterFeature.Config config, Node node)
+      throws Exception {
+    // Pass null for all unused (viz. visitor()) APIs to underscore their lack of use.
+    return new StyleTagExtractorVisitor(config, null, null).visit(null, node);
+  }
+  
+  private boolean getRevisitStatus(
+      Gadget gadget, boolean shouldRewriteUrl, CssRequestRewriter cssRewriter, List<Node> nodes)
+      throws Exception {
+    return new StyleTagExtractorVisitor(
+        config(true, true, shouldRewriteUrl), cssRewriter, proxyUriManager)
+        .revisit(gadget, nodes);
+  }
+  
+  private ContentRewriterFeature.Config config(
+      boolean enabled, boolean styleInc, boolean rewriteUrl) {
+    ContentRewriterFeature.Config config = createMock(ContentRewriterFeature.Config.class);
+    expect(config.isRewriteEnabled()).andReturn(enabled).anyTimes();
+    expect(config.getIncludedTags())
+        .andReturn(ImmutableSet.of(styleInc ? "style" : "foo")).anyTimes();
+    expect(config.shouldRewriteURL(isA(String.class))).andReturn(rewriteUrl).anyTimes();
+    replay(config);
+    return config;
+  }
+  
+  private Node addNodesToHtml(List<Node> nodes) throws Exception {
+    Node html = elem("html");
+    Node head = elem("head");
+    Node body = elem("body");
+    html.appendChild(head);
+    html.appendChild(body);
+    for (Node node : nodes) {
+      body.appendChild(node);
+    }
+    html.getOwnerDocument().appendChild(html);
+    return head;
+  }
+}