Author: gagan
Date: Tue Oct 19 01:30:17 2010
New Revision: 1024077
URL: http://svn.apache.org/viewvc?rev=1024077&view=rev
Log:
Patch by satya3656 | Issue 2044045: Adding ImageAttributeRewriter that adds the
height and width attributes if they are not specified. |
http://codereview.appspot.com/2044045/
Added:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/MultipleResourceHttpFetcher.java
(with props)
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ImageAttributeRewriter.java
(with props)
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/MultipleResourceHttpFetcherTest.java
(with props)
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ImageAttributeRewriterTest.java
(with props)
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ConcatProxyServlet.java
Added:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/MultipleResourceHttpFetcher.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/MultipleResourceHttpFetcher.java?rev=1024077&view=auto
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/MultipleResourceHttpFetcher.java
(added)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/MultipleResourceHttpFetcher.java
Tue Oct 19 01:30:17 2010
@@ -0,0 +1,161 @@
+/*
+ * 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.http;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.common.Pair;
+import org.apache.shindig.gadgets.GadgetException;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import java.util.concurrent.FutureTask;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * This class provides simple way for doing parallel fetches for multiple
+ * resourcs using FutureTask's.
+ */
+public class MultipleResourceHttpFetcher {
+ private final RequestPipeline requestPipeline;
+ private final Executor executor;
+
+ public MultipleResourceHttpFetcher(RequestPipeline requestPipeline, Executor
executor) {
+ this.requestPipeline = requestPipeline;
+ this.executor = executor;
+ }
+
+ /**
+ * Issue parallel requests to all resources that are needed.
+ *
+ * @param requests list of requests for which we want the resourses
+ * @return futureTasks List of Pairs of url,futureTask for all the requests
+ * in same order as specified.
+ */
+ public List<Pair<Uri, FutureTask<RequestContext>>>
fetchAll(List<HttpRequest> requests) {
+ List<Pair<Uri, FutureTask<RequestContext>>> futureTasks =
Lists.newArrayList();
+ for (HttpRequest request : requests) {
+ futureTasks.add(Pair.of(request.getUri(), createHttpFetcher(request)));
+ }
+
+ return futureTasks;
+ }
+
+ /**
+ * Issue parallel requests to all the resources that are needed ignoring
+ * duplicates.
+ *
+ * @param requests list of urls for which we want the image resourses
+ * @return futureTasks map of url -> futureTask for all the requests sent.
+ */
+ public Map<Uri, FutureTask<RequestContext>> fetchUnique(List<HttpRequest>
requests) {
+ Map<Uri, FutureTask<RequestContext>> futureTasks = Maps.newHashMap();
+ for (HttpRequest request : requests) {
+ Uri uri = request.getUri();
+ if (!futureTasks.containsKey(uri)) {
+ futureTasks.put(uri, createHttpFetcher(request));
+ }
+ }
+
+ return futureTasks;
+ }
+
+ // Fetch the content of the requested uri.
+ private FutureTask<RequestContext> createHttpFetcher(HttpRequest request) {
+ // Fetch the content of the requested uri.
+ FutureTask<RequestContext> httpFetcher =
+ new FutureTask<RequestContext>(new HttpFetchCallable(request,
requestPipeline));
+ executor.execute(httpFetcher);
+ return httpFetcher;
+ }
+
+ private class HttpFetchCallable implements Callable<RequestContext> {
+ private final HttpRequest httpReq;
+ private final RequestPipeline requestPipeline;
+
+ public HttpFetchCallable(HttpRequest httpReq, RequestPipeline
requestPipeline) {
+ this.httpReq = httpReq;
+ this.requestPipeline = requestPipeline;
+ }
+
+ public RequestContext call() {
+ HttpResponse httpResp = null;
+ GadgetException gadgetException = null;
+ try {
+ httpResp = requestPipeline.execute(httpReq);
+ } catch (GadgetException e){
+ gadgetException = e;
+ }
+ return new RequestContext(httpReq, httpResp, gadgetException);
+ }
+ }
+
+ // Encapsulates the response context of a single resource fetch.
+ public static class RequestContext {
+ private final HttpRequest httpReq;
+ private final HttpResponse httpResp;
+ private final GadgetException gadgetException;
+
+ public HttpRequest getHttpReq() {
+ return httpReq;
+ }
+
+ public HttpResponse getHttpResp() {
+ return httpResp;
+ }
+
+ public GadgetException getGadgetException() {
+ return gadgetException;
+ }
+
+ public RequestContext(HttpRequest httpReq, HttpResponse httpResp,
GadgetException ge) {
+ this.httpReq = httpReq;
+ this.httpResp = httpResp;
+ this.gadgetException = ge;
+ }
+
+ @Override
+ public int hashCode() {
+ return httpReq.hashCode()
+ ^ httpResp.hashCode()
+ ^ gadgetException.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof RequestContext)) {
+ return false;
+ }
+ RequestContext reqCxt = (RequestContext)obj;
+ return httpReq.equals(reqCxt.httpReq) &&
+ (httpResp != null ? httpResp.equals(reqCxt.httpResp) :
reqCxt.httpResp == null) &&
+ (gadgetException != null ?
gadgetException.equals(reqCxt.gadgetException) :
+ reqCxt.gadgetException == null);
+ }
+ }
+}
Propchange:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/MultipleResourceHttpFetcher.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ImageAttributeRewriter.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ImageAttributeRewriter.java?rev=1024077&view=auto
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ImageAttributeRewriter.java
(added)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ImageAttributeRewriter.java
Tue Oct 19 01:30:17 2010
@@ -0,0 +1,221 @@
+/*
+ * 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.common.collect.Lists;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+
+import org.apache.shindig.gadgets.http.RequestPipeline;
+import org.apache.shindig.gadgets.http.HttpRequest;
+import org.apache.shindig.gadgets.http.MultipleResourceHttpFetcher;
+import
org.apache.shindig.gadgets.http.MultipleResourceHttpFetcher.RequestContext;
+import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.Gadget;
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.common.xml.DomUtil;
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.common.uri.UriBuilder;
+import org.apache.sanselan.ImageFormat;
+import org.apache.sanselan.Sanselan;
+import org.apache.sanselan.ImageInfo;
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.common.byteSources.ByteSourceInputStream;
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+
+import java.util.logging.Logger;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.FutureTask;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.io.IOException;
+
+/**
+ * Rewriter that adds height/width attributes to <img> tags.
+ */
+public class ImageAttributeRewriter extends DomWalker.Rewriter {
+ private static final Logger LOG =
Logger.getLogger(ImageAttributeRewriter.class.getName());
+
+ @Inject
+ public ImageAttributeRewriter(RequestPipeline requestPipeline,
ExecutorService executor) {
+ super(new ImageAttributeVisitor(requestPipeline, executor));
+ }
+
+ /**
+ * Visitor that injects height/width attributes for <img> tags, if needed to
+ * reduce the page reflows.
+ */
+ public static class ImageAttributeVisitor implements DomWalker.Visitor {
+ private final RequestPipeline requestPipeline;
+ private final ExecutorService executor;
+
+ private static final String IMG_ATTR_CLASS_NAME_PREFIX =
"__shindig__image";
+
+ public ImageAttributeVisitor(RequestPipeline requestPipeline,
+ @Named("shindig.concat.executor")
ExecutorService executor) {
+ this.requestPipeline = requestPipeline;
+ this.executor = executor;
+ }
+
+ public VisitStatus visit(Gadget gadget, Node node) throws
RewritingException {
+ if (node.getNodeType() == Node.ELEMENT_NODE &&
+ node.getNodeName().toLowerCase().equals("img")) {
+ Element imageElement = (Element) node;
+
+ // we process the <img> tag when it does not have 'class' and 'id'
+ // attributes in order to avoid conflicts from css styles.
+ if ("".equals(imageElement.getAttribute("class")) &&
+ "".equals(imageElement.getAttribute("id")) &&
+ !"".equals(imageElement.getAttribute("src")) &&
+ "".equals(imageElement.getAttribute("height")) &&
+ "".equals(imageElement.getAttribute("width"))) {
+ return VisitStatus.RESERVE_NODE;
+ }
+ }
+ return VisitStatus.BYPASS;
+ }
+
+ @Override
+ public boolean revisit(Gadget gadget, List<Node> nodes) throws
RewritingException {
+ if (nodes.size() == 0) {
+ return false;
+ }
+ Node head = DomUtil.getFirstNamedChildNode(
+ nodes.get(0).getOwnerDocument().getDocumentElement(), "head");
+
+ if (head == null) {
+ // Should never occur; do for paranoia's sake.
+ return false;
+ }
+
+ List<HttpRequest> resourceRequests = Lists.newArrayList();
+ for (Node node : nodes) {
+ String imgSrc = ((Element) node).getAttribute("src");
+ Uri uri = UriBuilder.parse(imgSrc).toUri();
+ try {
+ resourceRequests.add(buildHttpRequest(gadget, uri));
+ } catch (GadgetException e) {
+ LOG.warning("Unable to process the image resource " + imgSrc);
+ }
+ }
+
+ MultipleResourceHttpFetcher fetcher =
+ new MultipleResourceHttpFetcher(requestPipeline, executor);
+ Map<Uri, FutureTask<RequestContext>> futureTasks =
fetcher.fetchUnique(resourceRequests);
+ String cssContent = processAllImgResources(nodes, futureTasks);
+
+ if (cssContent.length() > 0) {
+ Element style = nodes.get(0).getOwnerDocument().createElement("style");
+ style.setAttribute("type", "text/css");
+ style.setTextContent(cssContent);
+ head.insertBefore(style, head.getFirstChild());
+ }
+ return true;
+ }
+
+ /**
+ * The method process all the images, determine which of them are safe for
+ * injecting css styles for height/width extracted from the image metadata,
+ * and returns the string of css styles that needed to injected.
+ *
+ * @param nodes nodes list of nodes for this we want to height/width
+ * attribute injection in css.
+ * @param futureTasks futureTasks map of url -> futureTask for all the
requests sent.
+ * @return string contianing the css styles that needs to be injected.
+ */
+ private String processAllImgResources(List<Node> nodes,
+ Map<Uri, FutureTask<RequestContext>>
futureTasks) {
+ String cssContent = "";
+
+ for (int i = 0; i < nodes.size(); i++) {
+ Element imageElement = (Element) nodes.get(i);
+ String src = imageElement.getAttribute("src");
+ RequestContext requestCxt;
+
+ // Fetch the content of the requested uri.
+ try {
+ Uri imgUri = UriBuilder.parse(src).toUri();
+
+ try {
+ requestCxt = futureTasks.get(imgUri).get();
+ } catch (InterruptedException ie) {
+ throw new
GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, ie);
+ } catch (ExecutionException ie) {
+ throw new
GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, ie);
+ }
+
+ if (requestCxt.getGadgetException() != null) {
+ throw requestCxt.getGadgetException();
+ }
+
+ HttpResponse response = requestCxt.getHttpResp();
+ // Content header checking is fast so this is fine to do for every
+ // response.
+ ImageFormat imageFormat = Sanselan.guessFormat(
+ new ByteSourceInputStream(response.getResponse(),
imgUri.getPath()));
+
+ if (imageFormat == ImageFormat.IMAGE_FORMAT_UNKNOWN) {
+ // skip this node
+ continue;
+ }
+
+ // extract height and width from the actual image and set these
+ // attributes of the <img> tag.
+ ImageInfo imageInfo = Sanselan.getImageInfo(response.getResponse(),
+ imgUri.getPath());
+
+ if (imageInfo == null) {
+ continue;
+ }
+
+ int imageHeight = imageInfo.getHeight();
+ int imageWidth = imageInfo.getWidth();
+
+ if (imageHeight > 0 && imageWidth > 0 && imageHeight * imageWidth >
1) {
+ imageElement.setAttribute("class", IMG_ATTR_CLASS_NAME_PREFIX + i);
+ cssContent += "." + IMG_ATTR_CLASS_NAME_PREFIX + i + " {\n" +
+ " height: " + imageHeight + "px" + ";\n" +
+ " width: " + imageWidth + "px" + ";\n" +
+ "}\n";
+ }
+ } catch (ImageReadException e) {
+ LOG.warning("Unable to read reponnse for the image resource " + src);
+ } catch (GadgetException e) {
+ LOG.warning("Unable to fetch the image resource " + src);
+ } catch (IOException e) {
+ LOG.warning("Unable to parse the image resource " + src);
+ }
+ }
+
+ return cssContent;
+ }
+
+ // TODO(satya): Need to pass the request parameters as well ?
+ public static HttpRequest buildHttpRequest(Gadget gadget, Uri imgUri)
+ throws GadgetException {
+ HttpRequest req = new HttpRequest(imgUri);
+ req.setFollowRedirects(true);
+ return req;
+ }
+ }
+}
Propchange:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ImageAttributeRewriter.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ConcatProxyServlet.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ConcatProxyServlet.java?rev=1024077&r1=1024076&r2=1024077&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ConcatProxyServlet.java
(original)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ConcatProxyServlet.java
Tue Oct 19 01:30:17 2010
@@ -20,6 +20,7 @@ package org.apache.shindig.gadgets.servl
import com.google.inject.Inject;
import com.google.inject.name.Named;
+import com.google.common.collect.Lists;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
@@ -31,6 +32,8 @@ import org.apache.shindig.common.uri.Uri
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.MultipleResourceHttpFetcher;
+import
org.apache.shindig.gadgets.http.MultipleResourceHttpFetcher.RequestContext;
import org.apache.shindig.gadgets.http.RequestPipeline;
import org.apache.shindig.gadgets.rewrite.ResponseRewriterRegistry;
import org.apache.shindig.gadgets.rewrite.RewritingException;
@@ -38,9 +41,7 @@ import org.apache.shindig.gadgets.uri.Co
import org.apache.shindig.gadgets.uri.UriCommon.Param;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;
@@ -172,17 +173,12 @@ public class ConcatProxyServlet extends
cos = new VerbatimConcatOutputStream(response.getOutputStream());
}
- List<Pair<Uri, FutureTask<RequestContext>>> futureTasks =
- new ArrayList<Pair<Uri, FutureTask<RequestContext>>>();
+ List<HttpRequest> requests = Lists.newArrayList();
try {
for (Uri resourceUri : concatUri.getBatch()) {
try {
- HttpRequest httpReq = concatUri.makeHttpRequest(resourceUri);
- FutureTask<RequestContext> httpFetcher =
- new FutureTask<RequestContext>(new
HttpFetchCallable(httpReq));
- futureTasks.add(Pair.of(httpReq.getUri(), httpFetcher));
- executor.execute(httpFetcher);
+ requests.add(concatUri.makeHttpRequest(resourceUri));
} catch (GadgetException ge) {
if (cos.outputError(resourceUri, ge)) {
// True returned from outputError indicates a terminal error.
@@ -191,6 +187,10 @@ public class ConcatProxyServlet extends
}
}
+ MultipleResourceHttpFetcher parallelFetcher =
+ new MultipleResourceHttpFetcher(requestPipeline, executor);
+ List<Pair<Uri, FutureTask<RequestContext>>> futureTasks =
parallelFetcher.fetchAll(requests);
+
for (Pair<Uri, FutureTask<RequestContext>> futureTask : futureTasks) {
RequestContext requestCxt = null;
try {
@@ -359,50 +359,5 @@ public class ConcatProxyServlet extends
}
}
-
- // Encapsulates the response context of a single resource fetch.
- private static class RequestContext {
- private final HttpRequest httpReq;
- private final HttpResponse httpResp;
- private final GadgetException gadgetException;
-
- public HttpRequest getHttpReq() {
- return httpReq;
- }
-
- public HttpResponse getHttpResp() {
- return httpResp;
- }
-
- public GadgetException getGadgetException() {
- return gadgetException;
- }
-
- public RequestContext(HttpRequest httpReq, HttpResponse httpResp,
GadgetException ge) {
- this.httpReq = httpReq;
- this.httpResp = httpResp;
- this.gadgetException = ge;
- }
- }
-
- // Worker class responsible for fetching a single resource.
- public class HttpFetchCallable implements Callable<RequestContext> {
- private final HttpRequest httpReq;
-
- public HttpFetchCallable(HttpRequest httpReq) {
- this.httpReq = httpReq;
- }
-
- public RequestContext call() {
- HttpResponse httpResp = null;
- GadgetException gEx = null;
- try {
- httpResp = requestPipeline.execute(httpReq);
- } catch (GadgetException ge){
- gEx = ge;
- }
- return new RequestContext(httpReq, httpResp, gEx);
- }
- }
}
Added:
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/MultipleResourceHttpFetcherTest.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/MultipleResourceHttpFetcherTest.java?rev=1024077&view=auto
==============================================================================
---
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/MultipleResourceHttpFetcherTest.java
(added)
+++
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/MultipleResourceHttpFetcherTest.java
Tue Oct 19 01:30:17 2010
@@ -0,0 +1,115 @@
+/*
+ * 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.http;
+
+import com.google.common.collect.ImmutableList;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.eq;
+
+import org.apache.shindig.common.EasyMockTestCase;
+import org.apache.shindig.common.Pair;
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.common.uri.UriBuilder;
+import
org.apache.shindig.gadgets.http.MultipleResourceHttpFetcher.RequestContext;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.concurrent.*;
+import java.util.*;
+import java.io.*;
+
+/**
+ * Tests for {...@code MultipleResourceHttpFetcher}.
+ */
+public class MultipleResourceHttpFetcherTest extends EasyMockTestCase {
+ private RequestPipeline requestPipeline;
+ private transient ExecutorService executor =
Executors.newSingleThreadExecutor();
+ private MultipleResourceHttpFetcher fetcher;
+
+ private static final Uri IMG_URI =
+
UriBuilder.parse("org/apache/shindig/gadgets/rewrite/image/small.jpg").toUri();
+ private static final Uri CSS_URI =
+
UriBuilder.parse("org/apache/shindig/gadgets/rewrite/image/large.css").toUri();
+
+ private RequestContext reqCxt1;
+ private RequestContext reqCxt2;
+ private RequestContext reqCxt3;
+
+ @Before
+ public void setUp() throws Exception {
+ requestPipeline = mock(RequestPipeline.class);
+ fetcher = new MultipleResourceHttpFetcher(requestPipeline, executor);
+
+ reqCxt1 = createRequestContext(IMG_URI, "jpeg image", "image/jpeg");
+ reqCxt2 = createRequestContext(CSS_URI, "css files", "text/css");
+ reqCxt3 = createRequestContext(IMG_URI, "jpeg image", "image/jpeg");
+ }
+
+ @Test
+ public void testFetchAll() throws Exception {
+ List<HttpRequest> requests = createRequestArray();
+
+
expect(requestPipeline.execute(eq(reqCxt1.getHttpReq()))).andReturn(reqCxt1.getHttpResp());
+
expect(requestPipeline.execute(eq(reqCxt2.getHttpReq()))).andReturn(reqCxt2.getHttpResp());
+
expect(requestPipeline.execute(eq(reqCxt3.getHttpReq()))).andReturn(reqCxt3.getHttpResp());
+
+ replay();
+ List<Pair<Uri, FutureTask<RequestContext>>> futureTasks =
fetcher.fetchAll(requests);
+ assertEquals(3, futureTasks.size());
+ assertEquals(IMG_URI, futureTasks.get(0).one);
+ assertEquals(reqCxt1, futureTasks.get(0).two.get());
+ assertEquals(CSS_URI, futureTasks.get(1).one);
+ assertEquals(reqCxt2, futureTasks.get(1).two.get());
+ assertEquals(IMG_URI, futureTasks.get(2).one);
+ assertEquals(reqCxt3, futureTasks.get(2).two.get());
+ verify();
+ }
+
+ @Test
+ public void testFetchUnique() throws Exception {
+ List<HttpRequest> requests = createRequestArray();
+
+
expect(requestPipeline.execute(eq(reqCxt1.getHttpReq()))).andReturn(reqCxt1.getHttpResp());
+
expect(requestPipeline.execute(eq(reqCxt2.getHttpReq()))).andReturn(reqCxt2.getHttpResp());
+
+ replay();
+ Map<Uri, FutureTask<RequestContext>> futureTasks =
fetcher.fetchUnique(requests);
+ assertEquals(2, futureTasks.size());
+ assertTrue(futureTasks.containsKey(IMG_URI));
+ assertEquals(reqCxt1, futureTasks.get(IMG_URI).get());
+ assertTrue(futureTasks.containsKey(CSS_URI));
+ assertEquals(reqCxt2, futureTasks.get(CSS_URI).get());
+ verify();
+ }
+
+ private RequestContext createRequestContext(Uri uri, String content, String
mimeType)
+ throws IOException {
+ HttpRequest request = new HttpRequest(uri);
+
+ HttpResponse response = new
HttpResponseBuilder().addHeader("Content-Type", mimeType)
+ .setResponse(content.getBytes()).create();
+
+ return new RequestContext(request, response, null);
+ }
+
+ private List<HttpRequest> createRequestArray() {
+ return ImmutableList.of(reqCxt1.getHttpReq(), reqCxt2.getHttpReq(),
reqCxt3.getHttpReq());
+ }
+}
Propchange:
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/MultipleResourceHttpFetcherTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ImageAttributeRewriterTest.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ImageAttributeRewriterTest.java?rev=1024077&view=auto
==============================================================================
---
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ImageAttributeRewriterTest.java
(added)
+++
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ImageAttributeRewriterTest.java
Tue Oct 19 01:30:17 2010
@@ -0,0 +1,158 @@
+/*
+ * 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.common.collect.ImmutableList;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.eq;
+import static org.junit.Assert.assertEquals;
+
+import org.apache.shindig.gadgets.rewrite.DomWalker.Visitor.VisitStatus;
+import
org.apache.shindig.gadgets.rewrite.ImageAttributeRewriter.ImageAttributeVisitor;
+import org.apache.shindig.gadgets.http.RequestPipeline;
+import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.http.HttpResponseBuilder;
+import org.apache.shindig.gadgets.http.HttpRequest;
+import
org.apache.shindig.gadgets.http.MultipleResourceHttpFetcher.RequestContext;
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.common.uri.UriBuilder;
+import org.apache.commons.io.IOUtils;
+import org.junit.Test;
+import org.w3c.dom.Node;
+import org.easymock.IMocksControl;
+import org.easymock.EasyMock;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * Tests for {...@code ImageAttributeRewriter}
+ */
+public class ImageAttributeRewriterTest extends DomWalkerTestBase {
+ private RequestPipeline requestPipeline;
+ private IMocksControl control;
+ private transient ExecutorService executor =
Executors.newSingleThreadExecutor();
+ private static final String IMG_JPG_SMALL_URL =
+ "org/apache/shindig/gadgets/rewrite/image/small.jpg";
+ private static final String IMG_JPG_LARGE_URL =
+ "org/apache/shindig/gadgets/rewrite/image/large.jpg";
+
+ public void setUp() {
+ super.setUp();
+
+ control = EasyMock.createControl();
+ requestPipeline = control.createMock(RequestPipeline.class);
+ }
+
+ @Test
+ public void dontVisitImgTagWithClass() throws Exception {
+ Node img = elem("img", "class", "classname", "src", IMG_JPG_SMALL_URL);
+ assertEquals(VisitStatus.BYPASS, getVisitStatus(img));
+ }
+
+ @Test
+ public void dontVisitImgTagWithId() throws Exception {
+ Node img = elem("img", "id", "idname", "src", IMG_JPG_SMALL_URL);
+ assertEquals(VisitStatus.BYPASS, getVisitStatus(img));
+ }
+
+ @Test
+ public void dontVisitImgTagWithHeight() throws Exception {
+ Node img = elem("img", "height", "30", "src", IMG_JPG_SMALL_URL);
+ assertEquals(VisitStatus.BYPASS, getVisitStatus(img));
+ }
+
+ @Test
+ public void dontVisitImgTagWithWidth() throws Exception {
+ Node img = elem("img", "width", "70", "src", IMG_JPG_SMALL_URL);
+ assertEquals(VisitStatus.BYPASS, getVisitStatus(img));
+ }
+
+ @Test
+ public void dontVisitImgTagWithoutSrc() throws Exception {
+ Node img = elem("img");
+ assertEquals(VisitStatus.BYPASS, getVisitStatus(img));
+ }
+
+ @Test
+ public void visitImgTagWithSrc() throws Exception {
+ Node img = elem("img", "src", IMG_JPG_SMALL_URL, "title", "test image");
+ assertEquals(VisitStatus.RESERVE_NODE, getVisitStatus(img));
+ }
+
+ @Test
+ public void revisitZeroNodes() throws Exception {
+ assertEquals(false, getRevisitState(new ArrayList<Node>()));
+ }
+
+ @Test
+ public void revisit() throws Exception {
+ Node img1 = elem("img", "src", IMG_JPG_SMALL_URL);
+ Node img2 = elem("img", "src", IMG_JPG_LARGE_URL);
+ List<Node> nodes = ImmutableList.of(img1, img2);
+
+ RequestContext reqCxtImg1 = createRequestContext(IMG_JPG_SMALL_URL,
"image/jpeg");
+ RequestContext reqCxtImg2 = createRequestContext(IMG_JPG_LARGE_URL,
"image/jpeg");
+
+ expect(requestPipeline.execute(eq(reqCxtImg1.getHttpReq())))
+ .andReturn(reqCxtImg1.getHttpResp());
+ expect(requestPipeline.execute(eq(reqCxtImg2.getHttpReq())))
+ .andReturn(reqCxtImg2.getHttpResp());
+
+ Node html = htmlDoc(new Node[] {}, img1, img2);
+
+ String expectedContent = new StringBuilder()
+ .append(".__shindig__image0 {\n")
+ .append(" height: 16px;\n").append(" width: 16px;\n")
+ .append("}\n")
+ .append(".__shindig__image1 {\n")
+ .append(" height: 125px;\n").append(" width: 108px;\n")
+ .append("}\n").toString();
+
+ control.replay();
+ assertEquals(true, getRevisitState(nodes));
+ Node head = doc.getElementsByTagName("head").item(0);
+ assertEquals(1, head.getChildNodes().getLength());
+ assertEquals("style", head.getFirstChild().getNodeName());
+ assertEquals(expectedContent, head.getFirstChild().getTextContent());
+ control.verify();
+ }
+
+ private VisitStatus getVisitStatus(Node node) throws Exception {
+ return new ImageAttributeVisitor(requestPipeline,
executor).visit(gadget(), node);
+ }
+
+ private boolean getRevisitState(List<Node> nodes) throws Exception{
+ return new ImageAttributeVisitor(requestPipeline,
executor).revisit(gadget(), nodes);
+ }
+
+ private RequestContext createRequestContext(String resource, String
mimeType) throws Exception {
+ HttpRequest request = null;
+ Uri uri = UriBuilder.parse(resource).toUri();
+ request = ImageAttributeVisitor.buildHttpRequest(gadget(), uri);
+
+
+ byte[] bytes =
IOUtils.toByteArray(getClass().getClassLoader().getResourceAsStream(resource));
+ HttpResponse response = new
HttpResponseBuilder().addHeader("Content-Type", mimeType)
+ .setResponse(bytes).create();
+
+ return new RequestContext(request, response, null);
+ }
+}
Propchange:
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ImageAttributeRewriterTest.java
------------------------------------------------------------------------------
svn:eol-style = native