Author: mhermanto
Date: Fri Apr 8 17:35:32 2011
New Revision: 1090358
URL: http://svn.apache.org/viewvc?rev=1090358&view=rev
Log:
Incremental JS loading. Be able to serve partial JS, given that some libs have
been loaded. Idea: accumulate exports and externs of loaded JS libs (and their
transitively-dependent libs) for externs to requested JS libs (and their
transitively-dependent libs, minus explicitly-requested JS libs).
http://codereview.appspot.com/4376045/
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/CompilationProcessor.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/GetJsContentProcessor.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsResponseBuilder.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/SeparatorCommentingProcessor.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/DefaultJsCompiler.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/JsCompiler.java
shindig/trunk/java/gadgets/src/main/java16/org/apache/shindig/gadgets/rewrite/js/ClosureJsCompiler.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/CajaJsSubtractingProcessorTest.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/CompilationProcessorTest.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/GetJsContentProcessorTest.java
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/CompilationProcessor.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/CompilationProcessor.java?rev=1090358&r1=1090357&r2=1090358&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/CompilationProcessor.java
(original)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/CompilationProcessor.java
Fri Apr 8 17:35:32 2011
@@ -17,7 +17,6 @@
*/
package org.apache.shindig.gadgets.js;
-import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
import org.apache.shindig.gadgets.features.ApiDirective;
@@ -39,16 +38,16 @@ public class CompilationProcessor implem
*/
public boolean process(JsRequest request, JsResponseBuilder builder)
throws JsException {
- ImmutableList.Builder<String> externsBuilder = ImmutableList.builder();
- for (JsContent jsc : builder.build().getAllJsContent()) {
+ Iterable<JsContent> jsContents = builder.build().getAllJsContent();
+ for (JsContent jsc : jsContents) {
FeatureBundle bundle = jsc.getFeatureBundle();
if (bundle != null) {
- externsBuilder.addAll(bundle.getApis(ApiDirective.Type.JS, false));
+ builder.appendExterns(bundle.getApis(ApiDirective.Type.JS, false));
}
}
- JsResponse result = compiler.compile(request.getJsUri(),
- builder.build().getAllJsContent(), externsBuilder.build());
+ JsResponse result = compiler.compile(request.getJsUri(), jsContents,
+ builder.build().getExterns());
builder.clearJs().appendAllJs(result.getAllJsContent());
return true;
}
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/GetJsContentProcessor.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/GetJsContentProcessor.java?rev=1090358&r1=1090357&r2=1090358&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/GetJsContentProcessor.java
(original)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/GetJsContentProcessor.java
Fri Apr 8 17:35:32 2011
@@ -18,27 +18,29 @@
package org.apache.shindig.gadgets.js;
-import java.util.Collection;
-import java.util.List;
-
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.gadgets.features.ApiDirective;
import org.apache.shindig.gadgets.features.FeatureRegistry;
+import org.apache.shindig.gadgets.features.FeatureRegistry.FeatureBundle;
import org.apache.shindig.gadgets.features.FeatureResource;
import org.apache.shindig.gadgets.http.HttpResponse;
import org.apache.shindig.gadgets.rewrite.js.JsCompiler;
import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
import org.apache.shindig.gadgets.uri.UriStatus;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
/**
* Retrieves the requested Javascript code using a {@link JsProcessor}.
*/
public class GetJsContentProcessor implements JsProcessor {
- private static final Collection<String> EMPTY_SET = Sets.newHashSet();
private static final Joiner UNKNOWN_FEATURE_ERR = Joiner.on(", ");
private final FeatureRegistry registry;
@@ -56,58 +58,68 @@ public class GetJsContentProcessor imple
// Get JavaScript content from features aliases request.
JsUri jsUri = request.getJsUri();
GadgetContext ctx = new JsGadgetContext(jsUri);
- Collection<String> needed = jsUri.getLibs();
- List<String> unsupported = Lists.newLinkedList();
- FeatureRegistry.LookupResult lookup = registry.getFeatureResources(ctx,
needed, unsupported);
- if (!unsupported.isEmpty()) {
- throw new JsException(HttpResponse.SC_BAD_REQUEST,
- "Unknown feature(s): " + UNKNOWN_FEATURE_ERR.join(unsupported));
- }
+ List<FeatureBundle> requestedBundles = getAllBundles(ctx, jsUri.getLibs(),
false);
+ List<FeatureBundle> loadedBundles = getAllBundles(ctx,
jsUri.getLoadedLibs(), true);
- // Quick-and-dirty implementation of incremental JS loading.
- Collection<String> alreadyLoaded = EMPTY_SET;
- Collection<String> alreadyHaveLibs = jsUri.getLoadedLibs();
- if (!alreadyHaveLibs.isEmpty()) {
- alreadyLoaded = registry.getFeatures(alreadyHaveLibs);
+ Set<String> loadedFeatures = Sets.newHashSet();
+ for (FeatureBundle bundle : loadedBundles) {
+ loadedFeatures.add(bundle.getName());
+ builder.appendExterns(bundle.getApis(ApiDirective.Type.JS, true));
+ builder.appendExterns(bundle.getApis(ApiDirective.Type.JS, false));
}
// Collate all JS desired for the current request.
boolean isProxyCacheable = true;
- // Pre-process each feature.
- for (FeatureRegistry.FeatureBundle bundle : lookup.getBundles()) {
- if (alreadyLoaded.contains(bundle.getName())) continue;
+ for (FeatureBundle bundle : requestedBundles) {
+ // Exclude all transitively-dependent loaded features.
+ if (loadedFeatures.contains(bundle.getName())) {
+ continue;
+ }
builder.appendAllJs(compiler.getJsContent(jsUri, bundle));
for (FeatureResource featureResource : bundle.getResources()) {
isProxyCacheable = isProxyCacheable &&
featureResource.isProxyCacheable();
}
}
+
builder.setProxyCacheable(isProxyCacheable);
setResponseCacheTtl(builder, jsUri.getStatus());
return true;
}
+ private List<FeatureBundle> getAllBundles(GadgetContext ctx,
Collection<String> requested,
+ boolean loaded) throws JsException {
+ List<String> unsupported = Lists.newLinkedList();
+ FeatureRegistry.LookupResult lookup = registry.getFeatureResources(ctx,
requested, unsupported);
+ if (!unsupported.isEmpty()) {
+ String message = loaded ? "loaded" : "requested";
+ throw new JsException(HttpResponse.SC_BAD_REQUEST,
+ "Unknown " + message + " feature(s): " +
UNKNOWN_FEATURE_ERR.join(unsupported));
+ }
+ return lookup.getBundles();
+ }
+
/**
* Sets the cache TTL depending on the value of the {@link UriStatus} object.
*
- * @param resp The {@link JsResponseBuilder} object.
+ * @param builder The {@link JsResponseBuilder} object.
* @param vstatus The {@link UriStatus} object.
*/
- protected void setResponseCacheTtl(JsResponseBuilder resp, UriStatus
vstatus) {
+ protected void setResponseCacheTtl(JsResponseBuilder builder, UriStatus
vstatus) {
switch (vstatus) {
case VALID_VERSIONED:
// Versioned files get cached indefinitely
- resp.setCacheTtlSecs(-1);
+ builder.setCacheTtlSecs(-1);
break;
case VALID_UNVERSIONED:
// Unversioned files get cached for 1 hour.
- resp.setCacheTtlSecs(60 * 60);
+ builder.setCacheTtlSecs(60 * 60);
break;
case INVALID_VERSION:
// URL is invalid in some way, likely version mismatch.
// Indicate no-cache forcing subsequent requests to regenerate URLs.
- resp.setCacheTtlSecs(0);
+ builder.setCacheTtlSecs(0);
break;
}
}
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsResponseBuilder.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsResponseBuilder.java?rev=1090358&r1=1090357&r2=1090358&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsResponseBuilder.java
(original)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsResponseBuilder.java
Fri Apr 8 17:35:32 2011
@@ -18,24 +18,26 @@
package org.apache.shindig.gadgets.js;
-import javax.servlet.http.HttpServletResponse;
-
+import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
-import java.util.LinkedList;
-
import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+
/**
* A class with methods to create {@link JsResponse} objects.
*/
public class JsResponseBuilder {
- private LinkedList<JsContent> jsCode;
+ private static final String EXTERN_DELIM = ";\n";
+ private static final Joiner EXTERN_JOINER = Joiner.on(EXTERN_DELIM);
+
+ private List<JsContent> jsCode;
private final List<String> errors;
private int statusCode;
private int cacheTtlSecs;
private boolean proxyCacheable;
- private String externs;
+ private final StringBuilder externs;
public JsResponseBuilder() {
jsCode = Lists.newLinkedList();
@@ -43,23 +45,30 @@ public class JsResponseBuilder {
cacheTtlSecs = 0;
proxyCacheable = false;
errors = Lists.newLinkedList();
- externs = null;
+ externs = new StringBuilder();
}
public JsResponseBuilder(JsResponse response) {
- jsCode = Lists.newLinkedList(response.getAllJsContent());
- errors = Lists.newLinkedList(response.getErrors());
+ this();
+ if (response.getAllJsContent() != null) {
+ jsCode.addAll(Lists.newArrayList(response.getAllJsContent()));
+ }
+ if (response.getErrors() != null) {
+ errors.addAll(Lists.newArrayList(response.getErrors()));
+ }
+ if (response.getExterns() != null) {
+ externs.append(response.getExterns());
+ }
statusCode = response.getStatusCode();
cacheTtlSecs = response.getCacheTtlSecs();
proxyCacheable = response.isProxyCacheable();
- externs = response.getExterns();
}
/**
* Prepend a JS to the response.
*/
public JsResponseBuilder prependJs(JsContent jsContent) {
- jsCode.addFirst(jsContent);
+ jsCode.add(0, jsContent);
return this;
}
@@ -100,7 +109,7 @@ public class JsResponseBuilder {
* Prepends JS to the output.
*/
public JsResponseBuilder prependJs(String content, String name) {
- jsCode.addFirst(JsContent.fromText(content, name));
+ jsCode.add(0, JsContent.fromText(content, name));
return this;
}
@@ -176,10 +185,26 @@ public class JsResponseBuilder {
}
/**
- * Sets whether the compiled externs.
+ * Appends externs as string.
+ */
+ public JsResponseBuilder appendExterns(String externs) {
+ this.externs.append(externs).append(EXTERN_DELIM);
+ return this;
+ }
+
+ /**
+ * Appends externs as from list of strings.
+ */
+ public JsResponseBuilder appendExterns(List<String> externs) {
+ return appendExterns(EXTERN_JOINER.join(externs));
+ }
+
+ /**
+ * Deletes all externs in the builder.
*/
- public JsResponseBuilder setExterns(String externs) {
- this.externs = externs;
+ public JsResponseBuilder clearExterns() {
+ int last = externs.length();
+ this.externs.delete(0, last);
return this;
}
@@ -188,6 +213,6 @@ public class JsResponseBuilder {
*/
public JsResponse build() {
return new JsResponse(jsCode, statusCode, cacheTtlSecs, proxyCacheable,
- errors, externs);
+ errors, externs.toString());
}
}
\ No newline at end of file
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/SeparatorCommentingProcessor.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/SeparatorCommentingProcessor.java?rev=1090358&r1=1090357&r2=1090358&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/SeparatorCommentingProcessor.java
(original)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/SeparatorCommentingProcessor.java
Fri Apr 8 17:35:32 2011
@@ -25,7 +25,7 @@ public class SeparatorCommentingProcesso
public boolean process(JsRequest jsRequest, JsResponseBuilder builder) {
ImmutableList.Builder<JsContent> jsBuilder = ImmutableList.builder();
-
+
FeatureBundle lastFeature = null;
for (JsContent js : builder.build().getAllJsContent()) {
FeatureBundle feature = js.getFeatureBundle();
@@ -53,7 +53,7 @@ public class SeparatorCommentingProcesso
builder.clearJs().appendAllJs(jsBuilder.build());
return true;
}
-
+
private JsContent newComment(FeatureBundle bundle, boolean start) {
String tag = start ? "start" : "end";
return JsContent.fromFeature(
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/DefaultJsCompiler.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/DefaultJsCompiler.java?rev=1090358&r1=1090357&r2=1090358&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/DefaultJsCompiler.java
(original)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/DefaultJsCompiler.java
Fri Apr 8 17:35:32 2011
@@ -50,7 +50,7 @@ public class DefaultJsCompiler implement
return jsContent;
}
- public JsResponse compile(JsUri jsUri, Iterable<JsContent> content,
List<String> externs) {
+ public JsResponse compile(JsUri jsUri, Iterable<JsContent> content, String
externs) {
return new JsResponseBuilder().appendAllJs(content).build();
}
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/JsCompiler.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/JsCompiler.java?rev=1090358&r1=1090357&r2=1090358&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/JsCompiler.java
(original)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/JsCompiler.java
Fri Apr 8 17:35:32 2011
@@ -49,6 +49,6 @@ public interface JsCompiler {
* @param externs The externs.
* @return A compilation result object.
*/
- JsResponse compile(JsUri jsUri, Iterable<JsContent> content, List<String>
externs)
+ JsResponse compile(JsUri jsUri, Iterable<JsContent> content, String externs)
throws JsException;
}
Modified:
shindig/trunk/java/gadgets/src/main/java16/org/apache/shindig/gadgets/rewrite/js/ClosureJsCompiler.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java16/org/apache/shindig/gadgets/rewrite/js/ClosureJsCompiler.java?rev=1090358&r1=1090357&r2=1090358&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java16/org/apache/shindig/gadgets/rewrite/js/ClosureJsCompiler.java
(original)
+++
shindig/trunk/java/gadgets/src/main/java16/org/apache/shindig/gadgets/rewrite/js/ClosureJsCompiler.java
Fri Apr 8 17:35:32 2011
@@ -114,21 +114,12 @@ public class ClosureJsCompiler implement
return new Compiler(errorManager);
}
- private String toExternString(List<String> externs) {
- StringBuilder builder = new StringBuilder();
- for (String extern : externs) {
- builder.append(extern).append(";\n");
- }
- return builder.toString();
- }
-
- public JsResponse compile(JsUri jsUri, Iterable<JsContent> content,
List<String> externs)
+ public JsResponse compile(JsUri jsUri, Iterable<JsContent> content, String
externs)
throws JsException {
JsResponse exportResponse = defaultCompiler.compile(jsUri, content,
externs);
content = exportResponse.getAllJsContent();
- String externStr = toExternString(externs);
- String cacheKey = makeCacheKey(exportResponse.toJsString(), externStr,
jsUri);
+ String cacheKey = makeCacheKey(exportResponse.toJsString(), externs,
jsUri);
JsResponse cachedResult = cache.getElement(cacheKey);
if (cachedResult != null) {
lastResult = cachedResult;
@@ -141,7 +132,7 @@ public class ClosureJsCompiler implement
CompilerOptions options = getCompilerOptions();
if (!jsUri.isDebug() || options.isExternExportsEnabled()) {
List<JSSourceFile> allExterns = Lists.newArrayList();
- allExterns.add(JSSourceFile.fromCode("externs", externStr));
+ allExterns.add(JSSourceFile.fromCode("externs", externs));
List<JsContent> allContent = Lists.newLinkedList(content);
if (options.isExternExportsEnabled()) {
@@ -165,7 +156,7 @@ public class ClosureJsCompiler implement
cache.addElement(cacheKey, errorResult);
return errorResult;
}
-
+
String compiled = actualCompiler.toSource();
if (outputCorrelatedJs()) {
// Emit code correlated w/ original source.
@@ -177,7 +168,7 @@ public class ClosureJsCompiler implement
builder.appendJs(compiled, "[compiled]");
}
- builder.setExterns(result.externExport);
+ builder.clearExterns().appendExterns(result.externExport);
} else {
// Otherwise, return original content and null exports.
builder.appendAllJs(content);
Modified:
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/CajaJsSubtractingProcessorTest.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/CajaJsSubtractingProcessorTest.java?rev=1090358&r1=1090357&r2=1090358&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/CajaJsSubtractingProcessorTest.java
(original)
+++
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/CajaJsSubtractingProcessorTest.java
Fri Apr 8 17:35:32 2011
@@ -49,7 +49,7 @@ public class CajaJsSubtractingProcessorT
private List<JsContent> contents = Lists.newArrayList();
private JsResponse response;
private JsResponseBuilder builder;
-
+
private CajaJsSubtractingProcessor processor;
@Before
@@ -64,10 +64,10 @@ public class CajaJsSubtractingProcessorT
mockFeatureResource(ImmutableMap.of(UriCommon.Param.CAJOLE.getKey(),
"blah"))));
contents.add(JsContent.fromFeature(CAJA_CONTENT_JS, null, null,
mockFeatureResource(ImmutableMap.of(UriCommon.Param.CAJOLE.getKey(),
ATTRIB_VALUE))));
-
+
response = new JsResponse(contents, -1, -1, false, ERRORS, null);
builder = new JsResponseBuilder(response);
-
+
processor = new CajaJsSubtractingProcessor();
}
Modified:
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/CompilationProcessorTest.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/CompilationProcessorTest.java?rev=1090358&r1=1090357&r2=1090358&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/CompilationProcessorTest.java
(original)
+++
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/CompilationProcessorTest.java
Fri Apr 8 17:35:32 2011
@@ -67,7 +67,7 @@ public class CompilationProcessorTest {
JsRequest request = control.createMock(JsRequest.class);
expect(request.getJsUri()).andReturn(jsUri);
expect(compiler.compile(same(jsUri), eq(builder.build().getAllJsContent()),
- eq(Lists.newArrayList("extern3",
"extern4")))).andReturn(outputResponse);
+ eq("extern3;\n" + "extern4;\n"))).andReturn(outputResponse);
control.replay();
boolean status = processor.process(request, builder);
@@ -94,7 +94,7 @@ public class CompilationProcessorTest {
JsRequest request = control.createMock(JsRequest.class);
expect(request.getJsUri()).andReturn(jsUri);
List<String> emptyList = ImmutableList.of();
- expect(compiler.compile(same(jsUri),
eq(builder.build().getAllJsContent()), eq(emptyList)))
+ expect(compiler.compile(same(jsUri),
eq(builder.build().getAllJsContent()), eq("")))
.andThrow(new JsException(400, "foo"));
control.replay();
processor.process(request, builder);
Modified:
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/GetJsContentProcessorTest.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/GetJsContentProcessorTest.java?rev=1090358&r1=1090357&r2=1090358&view=diff
==============================================================================
---
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/GetJsContentProcessorTest.java
(original)
+++
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/GetJsContentProcessorTest.java
Fri Apr 8 17:35:32 2011
@@ -40,14 +40,17 @@ import org.junit.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
-
+import org.apache.shindig.gadgets.features.ApiDirective;
/**
* Tests for {@link GetJsContentProcessor}.
*/
public class GetJsContentProcessorTest {
- private static final String JS_CODE1 = "some JS data";
- private static final String JS_CODE2 = "some JS data";
+ private static final String JS_CODE1 = "js1";
+ private static final String JS_CODE2 = "js2";
+
+ private static final List<String> EMPTY_STRING_LIST =
ImmutableList.<String>of();
+ private static final List<FeatureBundle> EMPTY_BUNDLE_LIST =
ImmutableList.<FeatureBundle>of();
private IMocksControl control;
private FeatureRegistry registry;
@@ -70,88 +73,136 @@ public class GetJsContentProcessorTest {
@Test
public void testPopulatesResponseForUnversionedRequest() throws Exception {
- setExpectations(true, UriStatus.VALID_UNVERSIONED);
+ setupForVersionAndProxy(true, UriStatus.VALID_UNVERSIONED);
control.replay();
processor.process(request, response);
- checkResponse(true, 3600);
+ checkResponse(true, 3600, JS_CODE1 + JS_CODE2, "");
control.verify();
}
@Test
public void testPopulatesResponseForVersionedRequest() throws Exception {
- setExpectations(true, UriStatus.VALID_VERSIONED);
+ setupForVersionAndProxy(true, UriStatus.VALID_VERSIONED);
control.replay();
processor.process(request, response);
- checkResponse(true, -1);
+ checkResponse(true, -1, JS_CODE1 + JS_CODE2, "");
control.verify();
}
@Test
public void testPopulatesResponseForInvalidVersion() throws Exception {
- setExpectations(true, UriStatus.INVALID_VERSION);
+ setupForVersionAndProxy(true, UriStatus.INVALID_VERSION);
control.replay();
processor.process(request, response);
- checkResponse(true, 0);
+ checkResponse(true, 0, JS_CODE1 + JS_CODE2, "");
control.verify();
}
@Test
public void testPopulatesResponseForNoProxyCacheable() throws Exception {
- setExpectations(false, UriStatus.VALID_UNVERSIONED);
+ setupForVersionAndProxy(false, UriStatus.VALID_UNVERSIONED);
control.replay();
processor.process(request, response);
- checkResponse(false, 3600);
+ checkResponse(false, 3600, JS_CODE1 + JS_CODE2, "");
control.verify();
}
- private void setExpectations(boolean proxyCacheable, UriStatus uriStatus)
throws JsException {
+ @Test
+ public void testPopulateWithLoadedFeatures() throws Exception {
+ List<String> reqLibs = ImmutableList.of("feature1", "feature2");
+ List<String> loadLibs = ImmutableList.of("feature2");
+
+ FeatureResource resource1 = mockResource(true);
+ FeatureBundle bundle1 = mockBundle("feature1", null, null,
Lists.newArrayList(resource1));
+ FeatureBundle bundle2 = mockBundle("feature2", "export2", "extern2", null);
+
+ setupJsUriAndRegistry(UriStatus.VALID_UNVERSIONED,
+ reqLibs, ImmutableList.of(bundle1, bundle2),
+ loadLibs, ImmutableList.of(bundle2));
+
+ expect(compiler.getJsContent(jsUri, bundle1))
+ .andReturn(ImmutableList.<JsContent>of(
+ JsContent.fromFeature(JS_CODE1, null, null, null)));
+
+ control.replay();
+ processor.process(request, response);
+ checkResponse(true, 3600, JS_CODE1, "export2;\nextern2;\n");
+ control.verify();
+ }
+
+ private void setupForVersionAndProxy(boolean proxyCacheable, UriStatus
uriStatus) {
+ List<String> reqLibs = ImmutableList.of("feature");
+ List<String> loadLibs = EMPTY_STRING_LIST;
+
+ FeatureResource resource1 = mockResource(proxyCacheable);
+ FeatureResource resource2 = mockResource(proxyCacheable);
+ FeatureBundle bundle = mockBundle("feature", null, null,
+ Lists.newArrayList(resource1, resource2));
+
+ setupJsUriAndRegistry(uriStatus,
+ reqLibs, Lists.newArrayList(bundle),
+ loadLibs, EMPTY_BUNDLE_LIST);
+
+ expect(compiler.getJsContent(jsUri, bundle))
+ .andReturn(ImmutableList.<JsContent>of(
+ JsContent.fromFeature(JS_CODE1, null, bundle, resource1),
+ JsContent.fromFeature(JS_CODE2, null, bundle, resource2)));
+ }
+
+ private void setupJsUriAndRegistry(UriStatus uriStatus,
+ List<String> reqLibs, List<FeatureBundle> reqLookupBundles,
+ List<String> loadLibs, List<FeatureBundle> loadLookupBundles) {
+
expect(jsUri.getStatus()).andReturn(uriStatus);
- List<String> libs = ImmutableList.of("feature1", "feature2");
- expect(jsUri.getLibs()).andReturn(libs);
expect(jsUri.getContainer()).andReturn("container");
expect(jsUri.getContext()).andReturn(RenderingContext.CONFIGURED_GADGET);
expect(jsUri.isDebug()).andReturn(false);
- expect(jsUri.getLoadedLibs()).andReturn(ImmutableList.<String>of());
+ expect(jsUri.getLibs()).andReturn(reqLibs);
+ expect(jsUri.getLoadedLibs()).andReturn(loadLibs);
+
expect(request.getJsUri()).andReturn(jsUri);
- List<FeatureBundle> bundles = mockBundles(proxyCacheable);
- LookupResult lr = control.createMock(LookupResult.class);
- expect(lr.getBundles()).andReturn(bundles);
-
- expect(registry.getFeatureResources(isA(JsGadgetContext.class), eq(libs),
- eq(ImmutableList.<String>of()))).andReturn(lr);
- expect(compiler.getJsContent(jsUri, bundles.get(0)))
- .andReturn(ImmutableList.<JsContent>of(
- JsContent.fromFeature(JS_CODE1, "source1", bundles.get(0), null)));
- expect(compiler.getJsContent(jsUri, bundles.get(1)))
- .andReturn(ImmutableList.<JsContent>of(
- JsContent.fromFeature(JS_CODE2, "source2", bundles.get(1), null)));
+ LookupResult reqLookup = mockLookupResult(reqLookupBundles);
+ LookupResult loadLookup = mockLookupResult(loadLookupBundles);
+
+ expect(registry.getFeatureResources(isA(JsGadgetContext.class),
eq(reqLibs),
+ eq(EMPTY_STRING_LIST))).andReturn(reqLookup);
+ expect(registry.getFeatureResources(isA(JsGadgetContext.class),
eq(loadLibs),
+ eq(EMPTY_STRING_LIST))).andReturn(loadLookup);
}
- private List<FeatureBundle> mockBundles(boolean proxyCacheable) {
- FeatureBundle bundle1 = control.createMock(FeatureBundle.class);
- expect(bundle1.getName()).andReturn("feature1");
- FeatureResource resource1 = control.createMock(FeatureResource.class);
- expect(resource1.isProxyCacheable()).andReturn(proxyCacheable);
- List<FeatureResource> resources1 = Lists.newArrayList(resource1);
- expect(bundle1.getResources()).andReturn(resources1);
-
- FeatureBundle bundle2 = control.createMock(FeatureBundle.class);
- expect(bundle2.getName()).andReturn("feature2");
- FeatureResource resource2 = control.createMock(FeatureResource.class);
- if (proxyCacheable) {
- // Only consulted if the first bundle/resource is proxyCacheable.
- expect(resource2.isProxyCacheable()).andReturn(proxyCacheable);
- }
- List<FeatureResource> resources2 = Lists.newArrayList(resource2);
- expect(bundle2.getResources()).andReturn(resources2);
+ private LookupResult mockLookupResult(List<FeatureBundle> bundles) {
+ LookupResult result = control.createMock(LookupResult.class);
+ expect(result.getBundles()).andReturn(bundles);
+ return result;
+ }
+
+ private FeatureResource mockResource(boolean proxyCacheable) {
+ FeatureResource result = control.createMock(FeatureResource.class);
+ expect(result.isProxyCacheable()).andReturn(proxyCacheable).anyTimes();
+ return result;
+ }
- return Lists.newArrayList(bundle1, bundle2);
+ private FeatureBundle mockBundle(String name, String export, String extern,
List<FeatureResource> resources) {
+ FeatureBundle result = control.createMock(FeatureBundle.class);
+ expect(result.getName()).andReturn(name).anyTimes();
+ if (export != null) {
+ expect(result.getApis(ApiDirective.Type.JS,
true)).andReturn(ImmutableList.of(export));
+ }
+ if (extern != null) {
+ expect(result.getApis(ApiDirective.Type.JS,
false)).andReturn(ImmutableList.of(extern));
+ }
+ if (resources != null) {
+ expect(result.getResources()).andReturn(resources);
+ }
+ return result;
}
- private void checkResponse(boolean proxyCacheable, int expectedTtl) {
+ private void checkResponse(boolean proxyCacheable, int expectedTtl,
+ String jsString, String externsString) {
assertEquals(proxyCacheable, response.isProxyCacheable());
assertEquals(expectedTtl, response.getCacheTtlSecs());
- assertEquals(JS_CODE1 + JS_CODE2, response.build().toJsString());
+ assertEquals(jsString, response.build().toJsString());
+ assertEquals(externsString, response.build().getExterns());
}
}