Author: johnh
Date: Fri Sep 5 00:23:49 2008
New Revision: 692361
URL: http://svn.apache.org/viewvc?rev=692361&view=rev
Log:
Step #1 in migrating ParseTreeDefaultContentRewriter to its constituent parts:
three separate rewriters, all of which operate on a parse tree:
1. JsTagConcatCR: consolidates adjacent <script src> tags.
2. StyleLinkCR: rewrites image links in <style> blocks using a provided
LinkRewriter.
3. LinkingTagCR: rewrites content links in various tags using a provided
LinkRewriter.
With this change, each of these becomes independently configurable, and in fact
usable multiple times in a given rewriting chain if desired. Each is
constructed using either ContentRewriterFeature.Factory, LinkRewriter, or both.
The former generates a ContentRewriterFeature for a given GadgetSpec using
provided defaults. The Factory itself would be generated once, when configuring
the ContentRewriter instances that apply to a given Shindig installation in its
ContentRewriterRegistry.
All relevant code copied from what was previously in separate methods in
ParseTreeHtmlRewriter, with bits of semantics (notably regarding when the
rewriters actually apply) from [ParseTree]DefaultContentRewriter. Note that
each Rewriter independently makes its own decision as to whether or not it
applies for a given request.
As with ParseTreeDefaultContentRewriter, these changes presently do *not*
affect the default installation of Shindig, as they are not configured as
default Rewriters yet (soon).
These Rewriters are not yet complete due to missing implementations for the
HttpResponse ContentRewriter interface, pending implementation of an approach
for sharing a ParseTree to avoid multiple re-parsing (ContentRewriter interface
change or HttpResponse[Builder] helpers). Lastly, there are some commonalities
between these Rewriters which should soon be factored into helper base classes.
Added:
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/StyleLinksContentRewriter.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/FeatureBasedRewriterTestBase.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/LinkingTagContentRewriterTest.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleLinksContentRewriterTest.java
Removed:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ParseTreeDefaultContentRewriter.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ParseTreeHtmlRewriter.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ParseTreeHtmlRewriterTest.java
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeature.java
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeature.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeature.java?rev=692361&r1=692360&r2=692361&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeature.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeature.java
Fri Sep 5 00:23:49 2008
@@ -190,4 +190,30 @@
}
return fingerprint;
}
+
+ public static class Factory {
+ private final String defaultIncludeUrls;
+ private final String defaultExcludeUrls;
+ private final String defaultExpires;
+ private final Set<String> defaultIncludeTags;
+
+ public Factory(String includeUrls, String excludeUrls, String expires,
+ Set<String> includeTags) {
+ defaultIncludeUrls = includeUrls;
+ defaultExcludeUrls = excludeUrls;
+ defaultExpires = expires;
+ defaultIncludeTags = includeTags;
+ }
+
+ public ContentRewriterFeature get(GadgetSpec spec) {
+ ContentRewriterFeature rewriterFeature =
+ (ContentRewriterFeature)spec.getAttribute("content-rewrite");
+ if (rewriterFeature == null) {
+ rewriterFeature = new ContentRewriterFeature(spec, defaultIncludeUrls,
+ defaultExcludeUrls, defaultExpires, defaultIncludeTags);
+ spec.setAttribute("content-rewrite", rewriterFeature);
+ }
+ return rewriterFeature;
+ }
+ }
}
Added:
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=692361&view=auto
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/JsTagConcatContentRewriter.java
(added)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/JsTagConcatContentRewriter.java
Fri Sep 5 00:23:49 2008
@@ -0,0 +1,187 @@
+/*
+ * 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.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+
+import org.apache.shindig.common.util.Utf8UrlCoder;
+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.GadgetHtmlNode;
+import org.apache.shindig.gadgets.servlet.ProxyBase;
+import org.apache.shindig.gadgets.spec.GadgetSpec;
+
+public class JsTagConcatContentRewriter implements ContentRewriter {
+ private final static int MAX_URL_LENGTH = 1500;
+
+ private final ContentRewriterFeature.Factory rewriterFeatureFactory;
+ private final String concatUrlBase;
+
+ private static final String DEFAULT_CONCAT_URL_BASE = "/gadgets/concat?";
+
+ public JsTagConcatContentRewriter(ContentRewriterFeature.Factory
rewriterFeatureFactory,
+ String concatUrlBase) {
+ this.rewriterFeatureFactory = rewriterFeatureFactory;
+ if (concatUrlBase != null) {
+ this.concatUrlBase = concatUrlBase;
+ } else {
+ this.concatUrlBase = DEFAULT_CONCAT_URL_BASE;
+ }
+ }
+
+ public HttpResponse rewrite(HttpRequest request, HttpResponse original) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void rewrite(Gadget gadget) {
+ ContentRewriterFeature rewriterFeature =
rewriterFeatureFactory.get(gadget.getSpec());
+ if (!rewriterFeature.isRewriteEnabled() ||
+ !rewriterFeature.getIncludedTags().contains("script")) {
+ return;
+ }
+
+ // Bootstrap queue of children over which to iterate,
+ // ie. lists of siblings to potentially combine
+ Queue<GadgetHtmlNode> nodesToProcess =
+ new LinkedList<GadgetHtmlNode>();
+ nodesToProcess.add(gadget.getParseTree());
+
+
+ String concatBase = getJsConcatBase(gadget.getSpec(), rewriterFeature);
+
+ while (!nodesToProcess.isEmpty()) {
+ GadgetHtmlNode parentNode = nodesToProcess.remove();
+ if (!parentNode.isText()) {
+ List<GadgetHtmlNode> childList = parentNode.getChildren();
+
+ // Iterate over children next in depth-first fashion.
+ // Text nodes (such as <script src> processed here) will be ignored.
+ nodesToProcess.addAll(childList);
+
+ List<GadgetHtmlNode> toRemove = new ArrayList<GadgetHtmlNode>();
+ List<URI> scripts = new ArrayList<URI>();
+ boolean processScripts = false;
+ for (int i = 0; i < childList.size(); ++i) {
+ GadgetHtmlNode cur = childList.get(i);
+
+ // Find consecutive <script src=...> tags
+ if (!cur.isText() &&
+ cur.getTagName().equalsIgnoreCase("script") &&
+ cur.hasAttribute("src")) {
+ URI scriptUri = null;
+ try {
+ scriptUri =
+ gadget.getSpec().getUrl().resolve(new
URI(cur.getAttributeValue("src")));
+ } catch (URISyntaxException use) {
+ // Same behavior as JavascriptTagMerger
+ // Perhaps switch to ignoring script src instead?
+ throw new RuntimeException(use);
+ }
+ scripts.add(scriptUri);
+ toRemove.add(cur);
+ } else if (scripts.size() > 0 && cur.isText() &&
cur.getText().matches("\\s*")) {
+ // Whitespace after one or more scripts. Ignore and remove.
+ toRemove.add(cur);
+ } else if (scripts.size() > 0) {
+ processScripts = true;
+ }
+
+ if (i == (childList.size() - 1)) {
+ processScripts = true;
+ }
+
+ if (processScripts && scripts.size() > 0) {
+ // Tags found. Concatenate scripts together.
+ List<URI> concatUris = getConcatenatedUris(concatBase, scripts);
+
+ // Insert concatenated nodes before first match
+ for (URI concatUri : concatUris) {
+ GadgetHtmlNode newScript = new GadgetHtmlNode("script", null);
+ newScript.setAttribute("src", concatUri.toString());
+ parentNode.insertBefore(newScript, toRemove.get(0));
+ }
+
+ // Remove contributing match nodes
+ for (GadgetHtmlNode remove : toRemove) {
+ parentNode.removeChild(remove);
+ }
+
+ processScripts = false;
+ scripts.clear();
+ toRemove.clear();
+ }
+ }
+ }
+ }
+ }
+
+ private List<URI> getConcatenatedUris(String concatBase, List<URI> uris) {
+ List<URI> concatUris = new LinkedList<URI>();
+ int paramIndex = 1;
+ StringBuilder builder = null;
+ int maxUriLen = MAX_URL_LENGTH + concatBase.length();
+ try {
+ int uriIx = 0, lastUriIx = (uris.size() - 1);
+ for (URI uri : uris) {
+ if (paramIndex == 1) {
+ builder = new StringBuilder(concatBase);
+ } else {
+ builder.append("&");
+ }
+ builder.append(paramIndex).append("=")
+ .append(URLEncoder.encode(uri.toString(), "UTF-8"));
+ if (builder.length() > maxUriLen ||
+ uriIx == lastUriIx) {
+ // Went over URI length warning limit or on the last uri
+ concatUris.add(new URI(builder.toString()));
+ builder = null;
+ paramIndex = 0;
+ }
+ ++paramIndex;
+ ++uriIx;
+ }
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ return concatUris;
+ }
+
+ String getJsConcatBase(GadgetSpec spec, ContentRewriterFeature
rewriterFeature) {
+ return concatUrlBase +
+ ProxyBase.REWRITE_MIME_TYPE_PARAM +
+ "=text/javascript&" +
+ "gadget=" +
+ Utf8UrlCoder.encode(spec.getUrl().toString()) +
+ "&fp=" +
+ rewriterFeature.getFingerprint() +
+ '&';
+ }
+
+}
Added:
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=692361&view=auto
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/LinkingTagContentRewriter.java
(added)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/LinkingTagContentRewriter.java
Fri Sep 5 00:23:49 2008
@@ -0,0 +1,99 @@
+/*
+ * 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.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+
+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.GadgetHtmlNode;
+
+public class LinkingTagContentRewriter implements ContentRewriter {
+ private final LinkRewriter linkRewriter;
+ private final Map<String, Set<String>> tagAttributeTargets;
+
+ public LinkingTagContentRewriter(LinkRewriter linkRewriter,
+ Map<String, Set<String>> attributeTargets) {
+ this.linkRewriter = linkRewriter;
+ if (attributeTargets != null) {
+ this.tagAttributeTargets = attributeTargets;
+ } else {
+ this.tagAttributeTargets = getDefaultTargets();
+ }
+ }
+
+ public HttpResponse rewrite(HttpRequest request, HttpResponse original) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void rewrite(Gadget gadget) {
+ if (linkRewriter == null) {
+ // Sanity test.
+ return;
+ }
+
+ Queue<GadgetHtmlNode> nodesToProcess =
+ new LinkedList<GadgetHtmlNode>();
+ GadgetHtmlNode root = gadget.getParseTree();
+ if (root == null) {
+ return;
+ }
+
+ nodesToProcess.addAll(root.getChildren());
+
+ while (!nodesToProcess.isEmpty()) {
+ GadgetHtmlNode curNode = nodesToProcess.remove();
+ if (!curNode.isText()) {
+ // Depth-first iteration over children. Order doesn't matter anyway.
+ nodesToProcess.addAll(curNode.getChildren());
+
+ Set<String> curTagAttrs =
+ tagAttributeTargets.get(curNode.getTagName().toLowerCase());
+ if (curTagAttrs != null) {
+ for (String attrKey : curNode.getAttributeKeys()) {
+ if (curTagAttrs.contains(attrKey.toLowerCase())) {
+ String attrValue = curNode.getAttributeValue(attrKey);
+
+ // Attribute marked for rewriting: do it!
+ curNode.setAttribute(attrKey,
+ linkRewriter.rewrite(attrValue, gadget.getSpec().getUrl()));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private static Map<String, Set<String>> getDefaultTargets() {
+ Map<String, Set<String>> targets = new HashMap<String, Set<String>>();
+ targets.put("img", new HashSet<String>(Arrays.asList("src")));
+ targets.put("embed", new HashSet<String>(Arrays.asList("src")));
+ targets.put("link", new HashSet<String>(Arrays.asList("href")));
+ return targets;
+ }
+
+}
Added:
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=692361&view=auto
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleLinksContentRewriter.java
(added)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleLinksContentRewriter.java
Fri Sep 5 00:23:49 2008
@@ -0,0 +1,90 @@
+/*
+ * 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.LinkedList;
+import java.util.Queue;
+
+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.GadgetHtmlNode;
+import org.apache.shindig.gadgets.rewrite.ContentRewriterFeature;
+
+public class StyleLinksContentRewriter implements ContentRewriter {
+ // TODO: consider providing helper base class for node-visitor content
rewriters
+ private final ContentRewriterFeature.Factory rewriterFeatureFactory;
+ private final LinkRewriter linkRewriter;
+
+ public StyleLinksContentRewriter(ContentRewriterFeature.Factory
rewriterFeatureFactory,
+ LinkRewriter linkRewriter) {
+ this.rewriterFeatureFactory = rewriterFeatureFactory;
+ this.linkRewriter = linkRewriter;
+ }
+
+ public HttpResponse rewrite(HttpRequest request, HttpResponse original) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void rewrite(Gadget gadget) {
+ ContentRewriterFeature rewriterFeature =
rewriterFeatureFactory.get(gadget.getSpec());
+ if (linkRewriter == null ||
+ !rewriterFeature.isRewriteEnabled() ||
+ !rewriterFeature.getIncludedTags().contains("style")) {
+ return;
+ }
+
+ Queue<GadgetHtmlNode> nodesToProcess =
+ new LinkedList<GadgetHtmlNode>();
+ GadgetHtmlNode root = gadget.getParseTree();
+ if (root == null) {
+ return;
+ }
+
+ nodesToProcess.addAll(root.getChildren());
+
+ while (!nodesToProcess.isEmpty()) {
+ GadgetHtmlNode curNode = nodesToProcess.remove();
+ if (!curNode.isText()) {
+ // Depth-first iteration over children. Order doesn't matter anyway.
+ nodesToProcess.addAll(curNode.getChildren());
+
+ if (curNode.getTagName().equalsIgnoreCase("style")) {
+ String styleText = getNodeChildText(curNode);
+ curNode.clearChildren();
+ curNode.appendChild(new GadgetHtmlNode(
+ CssRewriter.rewrite(styleText, gadget.getSpec().getUrl(),
linkRewriter)));
+ }
+ }
+ }
+ }
+
+ private static String getNodeChildText(GadgetHtmlNode node) {
+ // TODO: move this to GadgetHtmlNode as a helper
+ StringBuilder builder = new StringBuilder();
+ for (GadgetHtmlNode child : node.getChildren()) {
+ if (child.isText()) {
+ builder.append(child.getText());
+ }
+ }
+ return builder.toString();
+ }
+
+}
Added:
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/FeatureBasedRewriterTestBase.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/FeatureBasedRewriterTestBase.java?rev=692361&view=auto
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/FeatureBasedRewriterTestBase.java
(added)
+++
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/FeatureBasedRewriterTestBase.java
Fri Sep 5 00:23:49 2008
@@ -0,0 +1,97 @@
+/*
+ * 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.easymock.classextension.EasyMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.classextension.EasyMock.replay;
+
+import org.apache.shindig.gadgets.Gadget;
+import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.gadgets.parse.GadgetHtmlParser;
+import org.apache.shindig.gadgets.parse.ParsedHtmlNode;
+import org.apache.shindig.gadgets.spec.GadgetSpec;
+import org.apache.shindig.gadgets.spec.View;
+
+import junit.framework.TestCase;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class FeatureBasedRewriterTestBase extends TestCase {
+ protected URI baseUri;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ baseUri = new URI("http://gadget.org/dir/gadget.xml");
+ }
+
+ protected ContentRewriterFeature.Factory mockContentRewriterFeatureFactory(
+ ContentRewriterFeature feature) {
+ return new MockRewriterFeatureFactory(feature);
+ }
+
+ protected ContentRewriterFeature makeFeature(String... includedTags) {
+ ContentRewriterFeature rewriterFeature =
+ EasyMock.createNiceMock(ContentRewriterFeature.class);
+ Set<String> tags = new HashSet<String>();
+ for (String tag : includedTags) {
+ tags.add(tag);
+ }
+ expect(rewriterFeature.isRewriteEnabled()).andReturn(true).anyTimes();
+ expect(rewriterFeature.getIncludedTags()).andReturn(tags).anyTimes();
+ expect(rewriterFeature.getFingerprint()).andReturn(-840722081).anyTimes();
+ replay(rewriterFeature);
+ return rewriterFeature;
+ }
+
+ protected String rewriteHelper(ContentRewriter rewriter, String s,
+ ParsedHtmlNode[] p) throws Exception {
+ GadgetHtmlParser parser = EasyMock.createNiceMock(GadgetHtmlParser.class);
+ List<ParsedHtmlNode> expected = p != null ? Arrays.asList(p) : null;
+ expect(parser.parse(s)).andReturn(expected).anyTimes();
+ View view = EasyMock.createNiceMock(View.class);
+ expect(view.getContent()).andReturn(s).anyTimes();
+ expect(view.getName()).andReturn(GadgetSpec.DEFAULT_VIEW).anyTimes();
+ GadgetSpec spec = EasyMock.createNiceMock(GadgetSpec.class);
+ expect(spec.getUrl()).andReturn(baseUri).anyTimes();
+ expect(spec.getView(GadgetSpec.DEFAULT_VIEW)).andReturn(view).anyTimes();
+ replay(parser, view, spec);
+ Gadget gadget = new Gadget(new GadgetContext(), spec, null, null, parser);
+ rewriter.rewrite(gadget);
+ return gadget.getContent();
+ }
+
+ private static class MockRewriterFeatureFactory extends
ContentRewriterFeature.Factory {
+ private final ContentRewriterFeature feature;
+
+ public MockRewriterFeatureFactory(ContentRewriterFeature feature) {
+ super(".*", "", "HTTP", null);
+ this.feature = feature;
+ }
+
+ @Override
+ public ContentRewriterFeature get(GadgetSpec spec) {
+ return feature;
+ }
+ }
+}
Added:
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=692361&view=auto
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/JsTagConcatContentRewriterTest.java
(added)
+++
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/JsTagConcatContentRewriterTest.java
Fri Sep 5 00:23:49 2008
@@ -0,0 +1,192 @@
+/*
+ * 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.easymock.classextension.EasyMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.classextension.EasyMock.replay;
+
+import org.apache.shindig.gadgets.parse.GadgetHtmlNodeTest;
+import org.apache.shindig.gadgets.parse.ParsedHtmlNode;
+import org.apache.shindig.gadgets.spec.GadgetSpec;
+
+public class JsTagConcatContentRewriterTest extends
FeatureBasedRewriterTestBase {
+ private ContentRewriterFeature jsFeature;
+ private JsTagConcatContentRewriter rewriter;
+ private String concatBase;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ jsFeature = makeFeature("script");
+ ContentRewriterFeature.Factory factory =
mockContentRewriterFeatureFactory(jsFeature);
+ rewriter = new JsTagConcatContentRewriter(factory, null);
+ GadgetSpec spec = EasyMock.createNiceMock(GadgetSpec.class);
+ expect(spec.getUrl()).andReturn(baseUri).anyTimes();
+ replay(spec);
+ concatBase = rewriter.getJsConcatBase(spec, jsFeature);
+ }
+
+ public void testJSMergePreserveNoExternal() throws Exception {
+ String s = "<script>\n"
+ + "doSomething\n"
+ + "</script>";
+ ParsedHtmlNode[] scriptKids = {
+ GadgetHtmlNodeTest.makeParsedTextNode("\ndoSomething\n")
+ };
+ ParsedHtmlNode[] p = {
+ GadgetHtmlNodeTest.makeParsedTagNode("script", null, scriptKids)
+ };
+ assertEquals(s, rewriteHelper(rewriter, s, p));
+ }
+
+ public void testJSMergePreserveNoScript() throws Exception {
+ String s
+ = "<html><div id=\"test\">ceci ne pas une script</div></html>";
+ String[][] attribs = { { "id", "test" } };
+ ParsedHtmlNode[] divKids = {
+ GadgetHtmlNodeTest.makeParsedTextNode("ceci ne pas une script")
+ };
+ ParsedHtmlNode[] htmlKids = {
+ GadgetHtmlNodeTest.makeParsedTagNode("div", attribs, divKids)
+ };
+ ParsedHtmlNode[] p = {
+ GadgetHtmlNodeTest.makeParsedTagNode("html", null, htmlKids)
+ };
+ assertEquals(s, rewriteHelper(rewriter, s, p));
+ }
+
+ public void testJSMergePreserveWithComment() throws Exception {
+ String s = "<script>" +
+ "<!--\ndoSomething\n-->" +
+ "</script>";
+ ParsedHtmlNode[] scriptKids = {
+ GadgetHtmlNodeTest.makeParsedTextNode("<!--\ndoSomething\n-->")
+ };
+ ParsedHtmlNode[] p = {
+ GadgetHtmlNodeTest.makeParsedTagNode("script", null, scriptKids)
+ };
+ assertEquals(s, rewriteHelper(rewriter, s, p));
+ }
+
+ public void testJSMergeSingleScriptReWrite() throws Exception {
+ String s = "<script src=\"http://a.b.com/1.js\"></script>";
+ String[][] attribs = { { "src", "http://a.b.com/1.js" } };
+ ParsedHtmlNode[] p = {
+ GadgetHtmlNodeTest.makeParsedTagNode("script", attribs, null)
+ };
+ String rewritten
+ = "<script src=\"" + concatBase +
"1=http%3A%2F%2Fa.b.com%2F1.js\"></script>";
+ assertEquals(rewritten, rewriteHelper(rewriter, s, p));
+ }
+
+ public void testJSMergeTwoScriptReWriteWithWhitespace() throws Exception {
+ String s = "<script src=\"http://a.b.com/1.js\"></script>\n"
+ + "<script src=\"http://a.b.com/2.js\"></script>";
+ String[][] attr1 = { { "src", "http://a.b.com/1.js" } };
+ String[][] attr2 = { { "src", "http://a.b.com/2.js" } };
+ ParsedHtmlNode[] p = {
+ GadgetHtmlNodeTest.makeParsedTagNode("script", attr1, null),
+ GadgetHtmlNodeTest.makeParsedTextNode("\n"),
+ GadgetHtmlNodeTest.makeParsedTagNode("script", attr2, null)
+ };
+ String rewritten
+ = "<script src=\"" + concatBase +
"1=http%3A%2F%2Fa.b.com%2F1.js&2=http%3A%2F%2Fa.b.com%2F2.js\"></script>";
+ assertEquals(rewritten, rewriteHelper(rewriter, s, p));
+ }
+
+ public void testJSMergeLeadAndTrailingScriptReWrite() throws Exception {
+ String s = "<script>\n"
+ + "doSomething\n"
+ + "</script>"
+ + "<script src=\"http://a.b.com/1.js\"></script>"
+ + "<script src=\"http://a.b.com/2.js\"></script>"
+ + "<script>"
+ + "doSomething\n"
+ + "</script>";
+ String[][] attr1 = { { "src", "http://a.b.com/1.js" } };
+ String[][] attr2 = { { "src", "http://a.b.com/2.js" } };
+ ParsedHtmlNode[] scriptKids = {
+ GadgetHtmlNodeTest.makeParsedTextNode("\ndoSomething\n")
+ };
+ ParsedHtmlNode[] p = {
+ GadgetHtmlNodeTest.makeParsedTagNode("script", null, scriptKids),
+ GadgetHtmlNodeTest.makeParsedTagNode("script", attr1, null),
+ GadgetHtmlNodeTest.makeParsedTagNode("script", attr2, null),
+ GadgetHtmlNodeTest.makeParsedTagNode("script", null, scriptKids)
+ };
+ String rewritten = "<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>"
+ + "<script>\n"
+ + "doSomething\n"
+ + "</script>";
+ assertEquals(rewritten, rewriteHelper(rewriter, s, p));
+ }
+
+ public void testJSMergeInterspersed() throws Exception {
+ String s = "<script src=\"http://a.b.com/1.js\"></script>"
+ + "<script src=\"http://a.b.com/2.js\"></script>"
+ + "<script><!-- doSomething --></script>"
+ + "<script src=\"http://a.b.com/3.js\"></script>"
+ + "<script src=\"http://a.b.com/4.js\"></script>";
+ String[][] attr1 = { { "src", "http://a.b.com/1.js" } };
+ String[][] attr2 = { { "src", "http://a.b.com/2.js" } };
+ String[][] attr3 = { { "src", "http://a.b.com/3.js" } };
+ String[][] attr4 = { { "src", "http://a.b.com/4.js" } };
+ ParsedHtmlNode[] scriptKids = {
+ GadgetHtmlNodeTest.makeParsedTextNode("<!-- doSomething -->")
+ };
+ ParsedHtmlNode[] p = {
+ GadgetHtmlNodeTest.makeParsedTagNode("script", attr1, null),
+ GadgetHtmlNodeTest.makeParsedTagNode("script", attr2, null),
+ GadgetHtmlNodeTest.makeParsedTagNode("script", null, scriptKids),
+ GadgetHtmlNodeTest.makeParsedTagNode("script", attr3, null),
+ GadgetHtmlNodeTest.makeParsedTagNode("script", attr4, null)
+ };
+ String rewritten =
+ "<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>";
+ assertEquals(rewritten, rewriteHelper(rewriter, s, p));
+ }
+
+ public void testJSMergeDerelativizeHostRelative() throws Exception {
+ String s = "<script src=\"/1.js\"></script>";
+ String[][] attr1 = { { "src", "/1.js" } };
+ ParsedHtmlNode[] p = {
+ GadgetHtmlNodeTest.makeParsedTagNode("script", attr1, null)
+ };
+ String rewritten
+ = "<script src=\"" + concatBase +
"1=http%3A%2F%2Fgadget.org%2F1.js\"></script>";
+ assertEquals(rewritten, rewriteHelper(rewriter, s, p));
+ }
+
+ public void testJSMergeDerelativizePathRelative() throws Exception {
+ String s = "<script src=\"1.js\"></script>";
+ String[][] attr1 = { { "src", "1.js" } };
+ ParsedHtmlNode[] p = {
+ GadgetHtmlNodeTest.makeParsedTagNode("script", attr1, null)
+ };
+ String rewritten
+ = "<script src=\"" + concatBase +
"1=http%3A%2F%2Fgadget.org%2Fdir%2F1.js\"></script>";
+ assertEquals(rewritten, rewriteHelper(rewriter, s, p));
+ }
+}
Added:
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=692361&view=auto
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/LinkingTagContentRewriterTest.java
(added)
+++
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/LinkingTagContentRewriterTest.java
Fri Sep 5 00:23:49 2008
@@ -0,0 +1,82 @@
+/*
+ * 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.net.URI;
+
+import org.apache.shindig.gadgets.parse.GadgetHtmlNodeTest;
+import org.apache.shindig.gadgets.parse.ParsedHtmlNode;
+
+public class LinkingTagContentRewriterTest extends
FeatureBasedRewriterTestBase {
+ private LinkRewriter pfxLinkRewriter;
+ private LinkingTagContentRewriter rewriter;
+
+ private static final String LINK_PREFIX = "px-";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ pfxLinkRewriter = new LinkRewriter() {
+ public String rewrite(String uri, URI context) {
+ // Just prefixes with LINK_PREFIX
+ return LINK_PREFIX + uri;
+ }
+ };
+ rewriter = new LinkingTagContentRewriter(pfxLinkRewriter, null);
+ }
+
+ public void testLinkingTagStandardRewrite() throws Exception {
+ String s = "<img src=\"http://a.b.com/img.gif\"></img>\n"
+ + "<IMG src=\"http://a.b.com/img2.gif\"/>\n"
+ + "<eMbeD src=\"http://a.b.com/some.mov\"/>\n"
+ + "<link href=\"http://a.b.com/link.html\"></link>";
+ String[][] img1attrib = { { "src", "http://a.b.com/img.gif" } };
+ String[][] img2attrib = { { "src", "http://a.b.com/img2.gif" } };
+ String[][] emb1attrib = { { "src", "http://a.b.com/some.mov" } };
+ String[][] href1attr = { { "href", "http://a.b.com/link.html" } };
+ ParsedHtmlNode[] p = {
+ GadgetHtmlNodeTest.makeParsedTagNode("img", img1attrib, null),
+ GadgetHtmlNodeTest.makeParsedTextNode("\n"),
+ GadgetHtmlNodeTest.makeParsedTagNode("IMG", img2attrib, null),
+ GadgetHtmlNodeTest.makeParsedTextNode("\n"),
+ GadgetHtmlNodeTest.makeParsedTagNode("eMbeD", emb1attrib, null),
+ GadgetHtmlNodeTest.makeParsedTextNode("\n"),
+ GadgetHtmlNodeTest.makeParsedTagNode("link", href1attr, null)
+ };
+ String rewritten = "<img src=\"" + LINK_PREFIX +
"http://a.b.com/img.gif\"/>\n"
+ + "<IMG src=\"" + LINK_PREFIX + "http://a.b.com/img2.gif\"/>\n"
+ + "<eMbeD src=\"" + LINK_PREFIX + "http://a.b.com/some.mov\"/>\n"
+ + "<link href=\"" + LINK_PREFIX + "http://a.b.com/link.html\"/>";
+ assertEquals(rewritten, rewriteHelper(rewriter, s, p));
+ }
+
+ public void testLinkingTagIgnoredWithNoRewriter() throws Exception {
+ String s = "<img src=\"http://a.b.com/img.gif\"></img>";
+ String[][] img1attrib = { { "src", "http://a.b.com/img.gif" } };
+ ParsedHtmlNode[] p = {
+ GadgetHtmlNodeTest.makeParsedTagNode("img", img1attrib, null),
+ };
+ assertEquals(s, rewriteHelper(new LinkingTagContentRewriter(null, null),
s, p));
+ }
+
+ public void testLinkingTagIgnoredWithBadParse() throws Exception {
+ String s = "<img src=\"http://a.b.com/img.gif></img>";
+ assertEquals(s, rewriteHelper(rewriter, s, null)); // null = couldn't
parse
+ }
+}
Added:
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=692361&view=auto
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleLinksContentRewriterTest.java
(added)
+++
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleLinksContentRewriterTest.java
Fri Sep 5 00:23:49 2008
@@ -0,0 +1,104 @@
+/*
+ * 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.net.URI;
+
+import org.apache.shindig.gadgets.parse.GadgetHtmlNodeTest;
+import org.apache.shindig.gadgets.parse.ParsedHtmlNode;
+
+public class StyleLinksContentRewriterTest extends
FeatureBasedRewriterTestBase {
+ private LinkRewriter pfxLinkRewriter;
+ private ContentRewriterFeature styleFeature;
+ private StyleLinksContentRewriter rewriter;
+
+ private static final String LINK_PREFIX = "px-";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ pfxLinkRewriter = new LinkRewriter() {
+ public String rewrite(String uri, URI context) {
+ // Just prefixes with LINK_PREFIX
+ return LINK_PREFIX + uri;
+ }
+ };
+ styleFeature = makeFeature("style");
+ ContentRewriterFeature.Factory factory =
mockContentRewriterFeatureFactory(styleFeature);
+ rewriter = new StyleLinksContentRewriter(factory, pfxLinkRewriter);
+ }
+
+ public void testStyleTagRewrites() throws Exception {
+ String css =
+ "div
{list-style-image:url('http://a.b.com/bullet.gif');list-style-position:outside;margin:5px;padding:0}\n"
+
+ ".someid
{background-image:url(http://a.b.com/bigimg.png);float:right;width:165px;height:23px;margin-top:4px;margin-left:5px}";
+ String s = "<style>" + css + "</style>";
+ ParsedHtmlNode[] styleKids = {
+ GadgetHtmlNodeTest.makeParsedTextNode(css)
+ };
+ ParsedHtmlNode[] p = {
+ GadgetHtmlNodeTest.makeParsedTagNode("style", null, styleKids)
+ };
+ String rewritten =
+ "<style>div {list-style-image:url(\"" + LINK_PREFIX +
"http://a.b.com/bullet.gif\");list-style-position:outside;margin:5px;padding:0}\n"
+
+ ".someid {background-image:url(\"" + LINK_PREFIX +
"http://a.b.com/bigimg.png\");float:right;width:165px;height:23px;margin-top:4px;margin-left:5px}</style>";
+ assertEquals(rewritten, rewriteHelper(rewriter, s, p));
+ }
+
+ public void testStyleTagRewritesIgnoredOnBadParse() throws Exception {
+ String css =
+ "div
{list-style-image:url('http://a.b.com/bullet.gif');list-style-position:outside;margin:5px;padding:0}\n"
+
+ ".someid
{background-image:url(http://a.b.com/bigimg.png);float:right;width:165px;height:23px;margin-top:4px;margin-left:5px}";
+ String s = "<style>" + css + "</style";
+ assertEquals(s, rewriteHelper(rewriter, s, null));
+ }
+
+ public void testStyleTagRewritesIgnoredOnNoFeatureKey() throws Exception {
+ ContentRewriterFeature overrideFeature = makeFeature("foo"); // doesn't
include "style"
+ ContentRewriterFeature.Factory factory =
mockContentRewriterFeatureFactory(overrideFeature);
+ StyleLinksContentRewriter overrideRewriter = new
StyleLinksContentRewriter(factory, pfxLinkRewriter);
+ String css =
+ "div
{list-style-image:url('http://a.b.com/bullet.gif');list-style-position:outside;margin:5px;padding:0}\n"
+
+ ".someid
{background-image:url(http://a.b.com/bigimg.png);float:right;width:165px;height:23px;margin-top:4px;margin-left:5px}";
+ String s = "<style>" + css + "</style>";
+ ParsedHtmlNode[] styleKids = {
+ GadgetHtmlNodeTest.makeParsedTextNode(css)
+ };
+ ParsedHtmlNode[] p = {
+ GadgetHtmlNodeTest.makeParsedTagNode("style", null, styleKids)
+ };
+ assertEquals(s, rewriteHelper(overrideRewriter, s, p));
+ }
+
+ public void testStyleTagRewritesIgnoredOnNullLinkRewriter() throws Exception
{
+ ContentRewriterFeature.Factory factory =
mockContentRewriterFeatureFactory(styleFeature);
+ StyleLinksContentRewriter overrideRewriter = new
StyleLinksContentRewriter(factory, null);
+ String css =
+ "div
{list-style-image:url('http://a.b.com/bullet.gif');list-style-position:outside;margin:5px;padding:0}\n"
+
+ ".someid
{background-image:url(http://a.b.com/bigimg.png);float:right;width:165px;height:23px;margin-top:4px;margin-left:5px}";
+ String s = "<style>" + css + "</style>";
+ ParsedHtmlNode[] styleKids = {
+ GadgetHtmlNodeTest.makeParsedTextNode(css)
+ };
+ ParsedHtmlNode[] p = {
+ GadgetHtmlNodeTest.makeParsedTagNode("style", null, styleKids)
+ };
+ assertEquals(s, rewriteHelper(overrideRewriter, s, p));
+ }
+}