You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by jo...@apache.org on 2011/03/18 18:16:12 UTC

svn commit: r1082977 - in /shindig/trunk/java/gadgets/src: main/java/org/apache/shindig/gadgets/features/ main/java/org/apache/shindig/gadgets/js/ main/java/org/apache/shindig/gadgets/rewrite/js/ main/java/org/apache/shindig/gadgets/servlet/ test/java/...

Author: johnh
Date: Fri Mar 18 17:16:11 2011
New Revision: 1082977

URL: http://svn.apache.org/viewvc?rev=1082977&view=rev
Log:
This refactoring functionally does nothing, but makes it possible to
track the provenance of JavaScript throughout the processing system.

I see two applications for this in the near term:
1. Code size profiling. With this data, profiling code size by feature
and by file, compiled and not compiled, becomes possible.

2. Provides the basis for correlating compiled JS with debug JS for use
in tooling.


Added:
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsContent.java
Modified:
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/BrowserSpecificFeatureResource.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/FeatureRegistry.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/FeatureResource.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/FeatureResourceLoader.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessor.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddOnloadFunctionProcessor.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/InjectJsInfoVariableProcessor.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsLoadProcessor.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsResponse.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/rewrite/js/DefaultJsCompiler.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompiler.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/JsCompiler.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsHandler.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleCacheKey.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessorTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddOnloadFunctionProcessorTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/DefaultJsProcessorRegistryTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/GetJsContentProcessorTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessorTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/JsLoadProcessorTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingGadgetRewriterTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/DefaultJsCompilerTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompilerTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerServiceTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/JsServletTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ModuleCacheTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/tags/FlashTagHandlerTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/uri/AllJsIframeVersionerTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/uri/DefaultJsVersionerTest.java

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/BrowserSpecificFeatureResource.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/BrowserSpecificFeatureResource.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/BrowserSpecificFeatureResource.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/BrowserSpecificFeatureResource.java Fri Mar 18 17:16:11 2011
@@ -96,6 +96,10 @@ public class BrowserSpecificFeatureResou
     return browserMatch.isEmpty() ? delegate.isProxyCacheable() : false;
   }
   
+  public String getName() {
+    return delegate.getName();
+  }
+  
   private boolean browserMatches() {
     if (browserMatch.isEmpty()) {
       // Not browser-sensitive.

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/FeatureRegistry.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/FeatureRegistry.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/FeatureRegistry.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/FeatureRegistry.java Fri Mar 18 17:16:11 2011
@@ -39,7 +39,6 @@ import org.apache.shindig.common.util.Re
 import org.apache.shindig.gadgets.GadgetContext;
 import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.RenderingContext;
-import org.apache.shindig.gadgets.features.FeatureRegistry.FeatureBundle;
 
 import java.io.File;
 import java.io.IOException;
@@ -467,7 +466,7 @@ public class FeatureRegistry {
       List<FeatureResource> resources = Lists.newArrayList();
       for (FeatureParser.ParsedFeature.Resource parsedResource : parsedBundle.getResources()) {
         if (parsedResource.getSource() == null) {
-          resources.add(new InlineFeatureResource(parsedResource.getContent()));
+          resources.add(new InlineFeatureResource(parsed.getName() + ":inline.js", parsedResource.getContent()));
         } else {
           // Load using resourceLoader
           resources.add(resourceLoader.load(parsedResource.getSource(),
@@ -502,10 +501,12 @@ public class FeatureRegistry {
   }
 
   private static final class InlineFeatureResource extends FeatureResource.Default {
+    private final String name;
     private final String content;
 
-    private InlineFeatureResource(String content) {
+    private InlineFeatureResource(String name, String content) {
       this.content = content;
+      this.name = name;
     }
 
     public String getContent() {
@@ -515,6 +516,10 @@ public class FeatureRegistry {
     public String getDebugContent() {
       return content;
     }
+    
+    public String getName() {
+      return name;
+    }
   }
 
   public static class LookupResult {

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/FeatureResource.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/FeatureResource.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/FeatureResource.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/FeatureResource.java Fri Mar 18 17:16:11 2011
@@ -42,6 +42,11 @@ public interface FeatureResource {
   boolean isProxyCacheable();
   
   /**
+   * @return A descriptive name used to reference the JS in various debug and stats contexts.
+   */
+  String getName();
+  
+  /**
    * Helper base class to avoid having to implement rarely-overridden isExternal/isProxyCacheable
    * functionality in FeatureResource.
    */
@@ -55,13 +60,15 @@ public interface FeatureResource {
     }
   }
   
-  public class Simple extends Default {
+  public class Simple extends Default {    
     private final String content;
     private final String debugContent;
+    private final String name;
     
-    public Simple(String content, String debugContent) {
+    public Simple(String content, String debugContent, String name) {
       this.content = content;
       this.debugContent = debugContent;
+      this.name = name;
     }
     
     public String getContent() {
@@ -71,5 +78,9 @@ public interface FeatureResource {
     public String getDebugContent() {
       return debugContent;
     }
+    
+    public String getName() {
+      return name;
+    }
   }
 }

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/FeatureResourceLoader.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/FeatureResourceLoader.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/FeatureResourceLoader.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/features/FeatureResourceLoader.java Fri Mar 18 17:16:11 2011
@@ -41,7 +41,7 @@ import java.util.logging.Logger;
  */
 public class FeatureResourceLoader {
 	  
-  //class name for logging purpose
+  // Class name for logging purpose
   private static final String classname = FeatureResourceLoader.class.getName();
   private static final Logger LOG = Logger.getLogger(classname, MessageKeys.MESSAGES);
   
@@ -147,10 +147,12 @@ public class FeatureResourceLoader {
   private class DualModeFileResource extends FeatureResource.Default {
     private final FileContent optContent;
     private final FileContent dbgContent;
+    private final String fileName;
     
     protected DualModeFileResource(String optFilePath, String dbgFilePath) {
       this.optContent = new FileContent(optFilePath);
       this.dbgContent = new FileContent(dbgFilePath);
+      this.fileName = dbgFilePath;
       Preconditions.checkArgument(optContent.get() != null || dbgContent.get() != null,
         "Problems reading resource: %s", dbgFilePath);
     }
@@ -165,6 +167,10 @@ public class FeatureResourceLoader {
       return dbg != null ? dbg : optContent.get();
     }
     
+    public String getName() {
+      return fileName;
+    }
+    
     private final class FileContent {
       private final String filePath;
       private long lastModified;
@@ -210,10 +216,12 @@ public class FeatureResourceLoader {
   private static final class DualModeStaticResource extends FeatureResource.Default {
     private final String content;
     private final String debugContent;
+    private final String path;
     
     private DualModeStaticResource(String path, String content, String debugContent) {
       this.content = content != null ? content : debugContent;
       this.debugContent = debugContent != null ? debugContent : content;
+      this.path = path;
       Preconditions.checkArgument(this.content != null, "Problems reading resource: %s", path);
     }
 
@@ -224,6 +232,10 @@ public class FeatureResourceLoader {
     public String getDebugContent() {
       return debugContent;
     }
+    
+    public String getName() {
+      return path;
+    }
   }
   
   private static final class UriResource implements FeatureResource {
@@ -289,5 +301,8 @@ public class FeatureResourceLoader {
       return content != null;
     }
 
+    public String getName() {
+      return uri.toString();
+    }
   }
 }

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessor.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessor.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessor.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessor.java Fri Mar 18 17:16:11 2011
@@ -23,6 +23,7 @@ import com.google.common.annotations.Vis
 import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
 
 public class AddJsLoadCallbackProcessor implements JsProcessor {
+  private static final String CODE_ID = "[jsload-callback]";
   
   @VisibleForTesting
   static final String JSL_CALLBACK_JS = "(function(){" +
@@ -37,7 +38,7 @@ public class AddJsLoadCallbackProcessor 
   public boolean process(JsRequest jsRequest, JsResponseBuilder builder) {
     JsUri jsUri = jsRequest.getJsUri();
     if (!jsUri.isNohint()) {
-      builder.addJsCode(JSL_CALLBACK_JS);
+      builder.appendJs(JSL_CALLBACK_JS, CODE_ID);
     }
     return true;
   }

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddOnloadFunctionProcessor.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddOnloadFunctionProcessor.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddOnloadFunctionProcessor.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/AddOnloadFunctionProcessor.java Fri Mar 18 17:16:11 2011
@@ -30,6 +30,7 @@ import javax.servlet.http.HttpServletRes
  * Adds code to call a function after the Javascript code has been interpreted.
  */
 public class AddOnloadFunctionProcessor implements JsProcessor {
+  private static final String CODE_ID = "[onload-processor]";
 
   @VisibleForTesting
   public static final String ONLOAD_FUNCTION_NAME_ERROR = "Invalid onload callback specified";
@@ -52,7 +53,7 @@ public class AddOnloadFunctionProcessor 
       if (!ONLOAD_FN_PATTERN.matcher(onloadStr).matches()) {
         throw new JsException(HttpServletResponse.SC_BAD_REQUEST, ONLOAD_FUNCTION_NAME_ERROR);
       }
-      builder.addJsCode(createOnloadScript(onloadStr));
+      builder.appendJs(createOnloadScript(onloadStr), CODE_ID);
     }
     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=1082977&r1=1082976&r2=1082977&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 Mar 18 17:16:11 2011
@@ -36,14 +36,14 @@ public class GetJsContentProcessor imple
     this.jsHandler = jsHandler;
   }
   
-  public boolean process(JsRequest request, JsResponseBuilder builder) {
+  public boolean process(JsRequest request, JsResponseBuilder builder) throws JsException {
     // Get JavaScript content from features aliases request.
     JsUri jsUri = request.getJsUri();
-    JsHandler.Response handlerResponse =
+    JsResponse handlerResponse =
         jsHandler.getJsContent(jsUri, request.getHost());
-    builder.addJsCode(handlerResponse.getJsData());
     builder.setProxyCacheable(handlerResponse.isProxyCacheable());    
     setResponseCacheTtl(builder, jsUri.getStatus());
+    builder.appendJs(handlerResponse.allJs());
     return true;
   }
 

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessor.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessor.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessor.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessor.java Fri Mar 18 17:16:11 2011
@@ -37,6 +37,7 @@ import java.util.List;
  * Used when loading embedded JS configuration in core.config/config.js.
  */
 public class InjectJsInfoVariableProcessor implements JsProcessor {
+  private static final String CODE_ID = "[jsload-code-info]";
 
   @VisibleForTesting
   static final String HINT_TEMPLATE = "(function(){" + 
@@ -57,7 +58,7 @@ public class InjectJsInfoVariableProcess
     if (!jsUri.isNohint()) {
       String uri = StringEscapeUtils.escapeJavaScript(getUri(jsUri));
       String features = getFeatures(jsUri);
-      builder.getJsCode().insert(0, String.format(HINT_TEMPLATE, uri, features));
+      builder.prependJs(String.format(HINT_TEMPLATE, uri, features), CODE_ID);
     }
     return true;
   }

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsContent.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsContent.java?rev=1082977&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsContent.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsContent.java Fri Mar 18 17:16:11 2011
@@ -0,0 +1,51 @@
+/*
+ * 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.js;
+
+/**
+ * Wrapper around JavaScript providing a way to track its provenance.
+ * Other metadata may be added as well, such as annotations regarding compilation,
+ * obfuscation, and so on.
+ */
+public class JsContent {
+  private final String content;
+  private final String source;
+  private final String feature;
+  
+  public JsContent(String content, String source) {
+    this(content, source, "[builtin]");
+  }
+  
+  public JsContent(String content, String source, String feature) {
+    this.content = content;
+    this.source = source;
+    this.feature = feature;
+  }
+  
+  public String get() {
+    return content;
+  }
+  
+  public String getSource() {
+    return source;
+  }
+  
+  public String getFeature() {
+    return feature;
+  }
+}

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsLoadProcessor.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsLoadProcessor.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsLoadProcessor.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsLoadProcessor.java Fri Mar 18 17:16:11 2011
@@ -32,6 +32,7 @@ import javax.servlet.http.HttpServletRes
  * Emit JS loader code if the jsload query parameter is present in the request.
  */
 public class JsLoadProcessor implements JsProcessor {
+  private static final String CODE_ID = "[jsloader-bootstrap]";
 
   @VisibleForTesting
   public static final String JSLOAD_ONLOAD_ERROR = "jsload requires onload";
@@ -88,7 +89,7 @@ public class JsLoadProcessor implements 
     int refresh = getCacheTtlSecs(jsUri);
     resp.setCacheTtlSecs(refresh);
     resp.setProxyCacheable(true);
-    resp.addJsCode(createJsloadScript(incUri));
+    resp.appendJs(createJsloadScript(incUri), CODE_ID);
   }
 
   private int getCacheTtlSecs(JsUri jsUri) {

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsResponse.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsResponse.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsResponse.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/js/JsResponse.java Fri Mar 18 17:16:11 2011
@@ -15,24 +15,29 @@
  * KIND, either express or implied. See the License for the
  * specific language governing permissions and limitations under the License.
  */
-
 package org.apache.shindig.gadgets.js;
 
+import java.util.Collections;
+import java.util.List;
 
 /**
  * An immutable object that contains the response for a JavaScript request.
+ * This object is used by JsHandler, JsProcessors, and JsCompiler alike.
  */
 public class JsResponse {
- 
-  String jsCode;
-  int cacheTtlSecs;
-  int statusCode;
-  boolean proxyCacheable;
-  
-  public JsResponse(String jsCode, int statusCode, int cachingPolicy, boolean proxyCacheable) {
-    this.jsCode = jsCode;
+  private final List<JsContent> jsCode;
+  private final List<String> errors;
+  private String codeString;
+  private final int cacheTtlSecs;
+  private final int statusCode;
+  private final boolean proxyCacheable;
+  
+  JsResponse(List<JsContent> jsCode, int statusCode, int cacheTtlSecs,
+      boolean proxyCacheable, List<String> errors) {
+    this.jsCode = Collections.unmodifiableList(jsCode);
+    this.errors = Collections.unmodifiableList(errors);
     this.statusCode = statusCode;
-    this.cacheTtlSecs = cachingPolicy;
+    this.cacheTtlSecs = cacheTtlSecs;
     this.proxyCacheable = proxyCacheable;
   }
   
@@ -40,6 +45,20 @@ public class JsResponse {
    * Returns the JavaScript code to serve.
    */
   public String getJsCode() {
+    if (codeString == null) {
+      StringBuilder sb = new StringBuilder();
+      for (JsContent js : allJs()) {
+        sb.append(js.get());
+      }
+      codeString = sb.toString();
+    }
+    return codeString;
+  }
+  
+  /**
+   * Returns an iterator starting at the beginning of all JS code in the response.
+   */
+  public Iterable<JsContent> allJs() {
     return jsCode;
   }
   
@@ -72,4 +91,11 @@ public class JsResponse {
   public boolean isProxyCacheable() {
     return proxyCacheable;
   }
+  
+  /**
+   * Returns a list of any error messages associated with this response.
+   */
+  public List<String> getErrors() {
+    return errors;
+  }
 }

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=1082977&r1=1082976&r2=1082977&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 Mar 18 17:16:11 2011
@@ -20,58 +20,83 @@ package org.apache.shindig.gadgets.js;
 
 import javax.servlet.http.HttpServletResponse;
 
+import com.google.common.collect.Lists;
+
+import java.util.LinkedList;
+
+import java.util.List;
+
 /**
  * A class with methods to create {@link JsResponse} objects.
  */
 public class JsResponseBuilder {
-
-  private StringBuilder jsCode;
+  private LinkedList<JsContent> jsCode;
+  private List<String> errors;
   private int statusCode;
   private int cacheTtlSecs;
   private boolean proxyCacheable;
   
   public JsResponseBuilder() {
-    jsCode = new StringBuilder();
+    jsCode = Lists.newLinkedList();
     statusCode = HttpServletResponse.SC_OK;
     cacheTtlSecs = 0;
     proxyCacheable = false;
+    errors = Lists.newLinkedList();
   }
 
   public JsResponseBuilder(JsResponse response) {
-    jsCode = new StringBuilder(response.jsCode);
-    statusCode = response.statusCode;
-    cacheTtlSecs = response.cacheTtlSecs;
-    proxyCacheable = response.proxyCacheable;
+    jsCode = Lists.newLinkedList(response.allJs());
+    errors = Lists.newLinkedList(response.getErrors());
+    statusCode = response.getStatusCode();
+    cacheTtlSecs = response.getCacheTtlSecs();
+    proxyCacheable = response.isProxyCacheable();
+  }
+  
+  /**
+   * Appends more JS to the response.
+   */
+  public JsResponseBuilder appendJs(JsContent jsContent) {
+    jsCode.add(jsContent);
+    return this;
   }
   
   /**
-   * Returns a StringBuilder to modify the current JavaScript code.
+   * Helper to append JS to the response w/ a name.
    */
-  public StringBuilder getJsCode() {
-    return jsCode;
+  public JsResponseBuilder appendJs(String content, String name) {
+    return appendJs(new JsContent(content, name));
   }
   
   /**
-   * Replaces the current JavaScript code with some new code.
+   * Helper to append a bunch of JS.
    */
-  public JsResponseBuilder setJsCode(CharSequence code) {
-    this.jsCode = new StringBuilder(code);
+  public JsResponseBuilder appendJs(Iterable<JsContent> jsBundle) {
+    for (JsContent content : jsBundle) {
+      appendJs(content);
+    }
     return this;
   }
-
+  
   /**
-   * Deletes all JavaScript code in the builder.
+   * Prepends JS to the output.
    */
-  public JsResponseBuilder clearJsCode() {
-    jsCode = new StringBuilder();
+  public JsResponseBuilder prependJs(String content, String name) {
+    jsCode.addFirst(new JsContent(content, name));
     return this;
   }
+  
+  /**
+   * Replaces the current JavaScript code with some new code.
+   */
+  public JsResponseBuilder setJs(String newContent, String name) {
+    return clearJs().appendJs(newContent, name);
+  }
 
   /**
-   * Appends some JavaScript code to the end of the current code.  
+   * Deletes all JavaScript code in the builder.
    */
-  public JsResponseBuilder addJsCode(CharSequence data) {
-    jsCode.append(data);
+  public JsResponseBuilder clearJs() {
+    this.jsCode = Lists.newLinkedList();
     return this;
   }
 
@@ -126,6 +151,6 @@ public class JsResponseBuilder {
    * Builds a {@link JsResponse} object with the provided data.
    */
   public JsResponse build() {
-    return new JsResponse(jsCode.toString(), statusCode, cacheTtlSecs, proxyCacheable);
+    return new JsResponse(jsCode, statusCode, cacheTtlSecs, proxyCacheable, errors);
   }
 }
\ No newline at end of file

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=1082977&r1=1082976&r2=1082977&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 Mar 18 17:16:11 2011
@@ -19,8 +19,13 @@ package org.apache.shindig.gadgets.rewri
 
 import org.apache.shindig.gadgets.features.FeatureRegistry.FeatureBundle;
 import org.apache.shindig.gadgets.features.FeatureResource;
+import org.apache.shindig.gadgets.js.JsContent;
+import org.apache.shindig.gadgets.js.JsResponse;
+import org.apache.shindig.gadgets.js.JsResponseBuilder;
 import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
 
+import com.google.common.collect.Lists;
+
 import java.util.List;
 
 /**
@@ -28,24 +33,25 @@ import java.util.List;
  */
 public class DefaultJsCompiler implements JsCompiler {
 
-  public String getJsContent(JsUri jsUri, FeatureBundle bundle) {
-    StringBuilder builder = new StringBuilder();
+  public Iterable<JsContent> getJsContent(JsUri jsUri, FeatureBundle bundle) {
+    List<JsContent> jsContent = Lists.newLinkedList();
     for (FeatureResource resource : bundle.getResources()) {
       String content = getFeatureContent(jsUri, resource);
       content = (content != null) ? content : "";
       if (resource.isExternal()) {
         // Support external/type=url feature serving through document.write()
-        builder.append("document.write('<script src=\"").append(content).append("\"></script>')");
+        jsContent.add(new JsContent("document.write('<script src=\"" + content + "\"></script>')",
+            "[external:" + content + "]", bundle.getName()));
       } else {
-        builder.append(content);
+        jsContent.add(new JsContent(content, resource.getName(), bundle.getName()));
       }
-      builder.append(";\n");
+      jsContent.add(new JsContent(";\n", "[separator]", bundle.getName()));
     }
-    return builder.toString();
+    return jsContent;
   }
 
-  public Result compile(JsUri jsUri, String content, List<String> externs) {
-    return new Result(content);
+  public JsResponse compile(JsUri jsUri, String content, List<String> externs) {
+    return new JsResponseBuilder().appendJs(content, "[passthrough]").build();
   }
 
   protected String getFeatureContent(JsUri jsUri, FeatureResource resource) {

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompiler.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompiler.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompiler.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompiler.java Fri Mar 18 17:16:11 2011
@@ -32,6 +32,9 @@ import org.apache.shindig.gadgets.featur
 import org.apache.shindig.gadgets.features.FeatureRegistry.FeatureBundle;
 import org.apache.shindig.gadgets.features.FeatureRegistry.LookupResult;
 import org.apache.shindig.gadgets.features.FeatureResource;
+import org.apache.shindig.gadgets.js.JsContent;
+import org.apache.shindig.gadgets.js.JsResponse;
+import org.apache.shindig.gadgets.js.JsResponseBuilder;
 import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
 
 import java.util.Collection;
@@ -56,23 +59,27 @@ public class ExportJsCompiler extends De
   }
 
   @Override
-  public String getJsContent(JsUri jsUri, FeatureBundle bundle) {
-    StringBuilder builder = new StringBuilder();
-    builder.append("\n/* feature=").append(bundle.getName()).append(" */\n");
-    builder.append(super.getJsContent(jsUri, bundle));
-    appendExportsForFeature(builder, jsUri, bundle);
-    builder.append("\n/* feature=").append(bundle.getName()).append(" */\n");
-    return builder.toString();
+  public Iterable<JsContent> getJsContent(JsUri jsUri, FeatureBundle bundle) {
+    List<JsContent> jsContent = Lists.newLinkedList();
+    jsContent.add(new JsContent("\n/* [start] feature=" + bundle.getName() +
+        " */\n", "[comment-marker-start]", bundle.getName()));
+    for (JsContent jsc : super.getJsContent(jsUri, bundle)) {
+      jsContent.add(jsc);
+    }
+    jsContent.add(getExportsForFeature(jsUri, bundle));
+    jsContent.add(new JsContent("\n/* [end] feature=" + bundle.getName() +
+        " */\n", "[comment-marker-end]", bundle.getName()));
+    return jsContent;
   }
 
   @Override
-  public Result compile(JsUri jsUri, String content, List<String> externs) {
+  public JsResponse compile(JsUri jsUri, String content, List<String> externs) {
     GadgetContext ctx = new JsGadgetContext(jsUri);
     StringBuilder builder = new StringBuilder();
     builder.append(getExportJsFeature(ctx));
     builder.append(content);
     // TODO: attach this to a real JS compiler jscomp.Compiler.
-    return new Result(builder.toString());
+    return new JsResponseBuilder().appendJs(builder.toString(), "[export-compiled]").build();
   }
 
   @Override
@@ -80,7 +87,7 @@ public class ExportJsCompiler extends De
     return resource.getDebugContent();
   }
 
-  private void appendExportsForFeature(StringBuilder out, JsUri jsUri, FeatureBundle bundle) {
+  private JsContent getExportsForFeature(JsUri jsUri, FeatureBundle bundle) {
     List<String> exports = Lists.newArrayList();
 
     // Add exports of bundle, regardless.
@@ -94,9 +101,12 @@ public class ExportJsCompiler extends De
       }
     }
 
+    StringBuilder sb = new StringBuilder();
     for (Input input : generateInputs(exports)) {
-      out.append(input.toExportStatement());
+      sb.append(input.toExportStatement());
     }
+    
+    return new JsContent(sb.toString(), "[generated-symbol-exports]", bundle.getName());
   }
 
   private String getExportJsFeature(GadgetContext context) {

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=1082977&r1=1082976&r2=1082977&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 Mar 18 17:16:11 2011
@@ -20,6 +20,8 @@ package org.apache.shindig.gadgets.rewri
 import com.google.inject.ImplementedBy;
 
 import org.apache.shindig.gadgets.features.FeatureRegistry.FeatureBundle;
+import org.apache.shindig.gadgets.js.JsContent;
+import org.apache.shindig.gadgets.js.JsResponse;
 import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
 
 import java.util.List;
@@ -37,7 +39,7 @@ public interface JsCompiler {
    * @param bundle The feature bundle.
    * @return Processed feature JS.
    */
-  String getJsContent(JsUri jsUri, FeatureBundle bundle);
+  Iterable<JsContent> getJsContent(JsUri jsUri, FeatureBundle bundle);
 
   /**
    * Compiles the provided code with the provided list of external symbols.
@@ -46,28 +48,5 @@ public interface JsCompiler {
    * @param externs The externs.
    * @return A compilation result object.
    */
-  Result compile(JsUri jsUri, String content, List<String> externs);
-
-  static class Result {
-    private final String compiled;
-    private final List<String> errors;
-
-    public Result(String compiled) {
-      this.compiled = compiled;
-      this.errors = null;
-    }
-
-    public Result(List<String> errors) {
-      this.compiled = null;
-      this.errors = errors;
-    }
-
-    public String getCode() {
-      return compiled;
-    }
-
-    public List<String> getErrors() {
-      return errors;
-    }
-  }
+  JsResponse compile(JsUri jsUri, String content, List<String> externs);
 }

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java Fri Mar 18 17:16:11 2011
@@ -26,7 +26,6 @@ import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.inject.Inject;
@@ -47,6 +46,8 @@ import org.apache.shindig.gadgets.Gadget
 import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.RenderingContext;
 import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.js.JsException;
+import org.apache.shindig.gadgets.js.JsResponse;
 import org.apache.shindig.gadgets.process.ProcessingException;
 import org.apache.shindig.gadgets.process.Processor;
 import org.apache.shindig.gadgets.servlet.CajaContentRewriter.CajoledResult;
@@ -208,13 +209,13 @@ public class GadgetsHandlerService {
     String content = null;
     Long expireMs = null;
     if (isFieldIncluded(fields, "jsContent")) {
-      JsHandler.Response response = jsHandler.getJsContent(jsUri, servedUri.getAuthority());
-      content = response.getJsData().toString();
-      if (content.length() == 0) {
-        // No content, meaning no such feature
-        throw new ProcessingException("Feature(s) " + Joiner.on(",").join(jsUri.getLibs())
-            + " not found", HttpResponse.SC_NOT_FOUND);
+      JsResponse response = null;
+      try {
+        response = jsHandler.getJsContent(jsUri, servedUri.getAuthority());
+      } catch (JsException e) {
+        throw new ProcessingException(e.getMessage(), e.getStatusCode());
       }
+      content = response.getJsCode();
       if (response.isProxyCacheable()) {
         expireMs = timeSource.currentTimeMillis() + (HttpUtil.getDefaultTtl() * 1000);
       }

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsHandler.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsHandler.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsHandler.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsHandler.java Fri Mar 18 17:16:11 2011
@@ -32,6 +32,10 @@ import org.apache.shindig.gadgets.config
 import org.apache.shindig.gadgets.features.ApiDirective;
 import org.apache.shindig.gadgets.features.FeatureRegistry;
 import org.apache.shindig.gadgets.features.FeatureResource;
+import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.js.JsException;
+import org.apache.shindig.gadgets.js.JsResponse;
+import org.apache.shindig.gadgets.js.JsResponseBuilder;
 import org.apache.shindig.gadgets.rewrite.js.JsCompiler;
 import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
 
@@ -47,8 +51,10 @@ import java.util.logging.Logger;
  */
 @Singleton
 public class JsHandler {
+  private static final String CONFIG_INIT_ID = "[config-injection]";
   private static final Collection<String> EMPTY_SET = Sets.newHashSet();
   private static final Logger LOG = Logger.getLogger(JsHandler.class.getName());
+  private static final Joiner UNKNOWN_FEATURE_ERR = Joiner.on(", ");
 
   protected final FeatureRegistry registry;
   protected final ContainerConfig containerConfig;
@@ -77,12 +83,17 @@ public class JsHandler {
    * @param host The name of the host the request was directed to.
    * @return JsHandlerResponse object that contains JavaScript data and cacheable flag.
    */
-  public Response getJsContent(final JsUri jsUri, String host) {
+  public JsResponse getJsContent(final JsUri jsUri, String host) throws JsException {
     GadgetContext ctx = new JsGadgetContext(jsUri);
     Collection<String> needed = jsUri.getLibs();
-    boolean isProxyCacheable = true;
 
-    FeatureRegistry.LookupResult lookup = registry.getFeatureResources(ctx, needed, null);
+    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" + (unsupported.size() > 1 ? "s" : "") +
+          ": " + UNKNOWN_FEATURE_ERR.join(unsupported));
+    }
 
     // Quick-and-dirty implementation of incremental JS loading.
     Collection<String> alreadyLoaded = EMPTY_SET;
@@ -92,25 +103,27 @@ public class JsHandler {
     }
 
     // Collate all JS desired for the current request.
-    StringBuilder jsData = new StringBuilder();
+    boolean isProxyCacheable = true;
+    JsResponseBuilder responseBuilder = new JsResponseBuilder();
     List<String> allExterns = Lists.newArrayList();
 
     // Pre-process each feature.
     for (FeatureRegistry.FeatureBundle bundle : lookup.getBundles()) {
       if (alreadyLoaded.contains(bundle.getName())) continue;
-      jsData.append(compiler.getJsContent(jsUri, bundle));
+      responseBuilder.appendJs(compiler.getJsContent(jsUri, bundle));
       allExterns.addAll(bundle.getApis(ApiDirective.Type.JS, false));
       for (FeatureResource featureResource : bundle.getResources()) {
         isProxyCacheable = isProxyCacheable && featureResource.isProxyCacheable();
       }
     }
+    responseBuilder.setProxyCacheable(isProxyCacheable);
 
     // Compile all pre-processed features.
-    JsCompiler.Result result = compiler.compile(jsUri, jsData.toString(), allExterns);
+    JsResponse result = compiler.compile(jsUri, responseBuilder.build().getJsCode(), allExterns);
 
-    String code = result.getCode();
+    String code = result.getJsCode();
     if (code != null) {
-      jsData = new StringBuilder(code);
+      responseBuilder.setJs(code, "[compiled]");
     } else {
       warn(result);
     }
@@ -137,41 +150,22 @@ public class JsHandler {
             contributor.contribute(config, container, host);
           }
         }
-        jsData.append("gadgets.config.init(").append(JsonSerializer.serialize(config)).append(");\n");
+        // TODO: Convert this to a JsProcessor.
+        responseBuilder.appendJs(
+            "gadgets.config.init(" + JsonSerializer.serialize(config) + ");\n", CONFIG_INIT_ID);
       }
     }
 
     // Wrap up the response.
-    return new Response(jsData, isProxyCacheable);
+    return responseBuilder.build();
   }
 
-  protected void warn(JsCompiler.Result result) {
+  protected void warn(JsResponse result) {
     LOG.log(Level.WARNING, "Continuing with un-compiled content. " +
         "JS Compilation error: " + Joiner.on(", ").join(result.getErrors()));
   }
 
   /**
-   * Define the response data from JsHandler.
-   */
-  public static class Response {
-    private final boolean isProxyCacheable;
-    private final StringBuilder jsData;
-
-    public Response(StringBuilder jsData, boolean isProxyCacheable) {
-      this.jsData = jsData;
-      this.isProxyCacheable = isProxyCacheable;
-    }
-
-    public boolean isProxyCacheable() {
-      return isProxyCacheable;
-    }
-
-    public StringBuilder getJsData() {
-      return jsData;
-    }
-  }
-
-  /**
    * GadgetContext for JsHandler called by FeatureRegistry when fetching the resources.
    */
   protected static class JsGadgetContext extends GadgetContext {

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleCacheKey.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleCacheKey.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleCacheKey.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleCacheKey.java Fri Mar 18 17:16:11 2011
@@ -21,8 +21,6 @@ package org.apache.shindig.gadgets.servl
 import com.google.caja.parser.ParseTreeNode;
 import com.google.caja.plugin.stages.JobCache;
 import com.google.caja.util.ContentType;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NamedNodeMap;
 

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessorTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessorTest.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessorTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddJsLoadCallbackProcessorTest.java Fri Mar 18 17:16:11 2011
@@ -50,7 +50,7 @@ public class AddJsLoadCallbackProcessorT
     control.replay();
     assertTrue(processor.process(request, response));
     assertEquals(AddJsLoadCallbackProcessor.JSL_CALLBACK_JS,
-        response.getJsCode().toString());
+        response.build().getJsCode());
     control.verify();
   }
 
@@ -59,7 +59,7 @@ public class AddJsLoadCallbackProcessorT
     EasyMock.expect(jsUri.isNohint()).andReturn(true);
     control.replay();
     assertTrue(processor.process(request, response));
-    assertEquals("", response.getJsCode().toString());
+    assertEquals("", response.build().getJsCode());
     control.verify();
   }
 }

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddOnloadFunctionProcessorTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddOnloadFunctionProcessorTest.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddOnloadFunctionProcessorTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/AddOnloadFunctionProcessorTest.java Fri Mar 18 17:16:11 2011
@@ -83,7 +83,7 @@ public class AddOnloadFunctionProcessorT
     assertTrue(processor.process(request, response));
     assertEquals(HttpServletResponse.SC_OK, response.getStatusCode());
     String expectedBody = String.format(AddOnloadFunctionProcessor.ONLOAD_JS_TPL, ONLOAD_FUNCTION);
-    assertEquals(expectedBody, response.getJsCode().toString());
+    assertEquals(expectedBody, response.build().getJsCode());
     control.verify();
   }
 }

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/DefaultJsProcessorRegistryTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/DefaultJsProcessorRegistryTest.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/DefaultJsProcessorRegistryTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/DefaultJsProcessorRegistryTest.java Fri Mar 18 17:16:11 2011
@@ -56,14 +56,14 @@ public class DefaultJsProcessorRegistryT
   public void testProcessorModifiesResponse() throws Exception {
     JsProcessor processor = new JsProcessor() {
       public boolean process(JsRequest request, JsResponseBuilder builder) {
-        builder.setJsCode(JS_CODE);
+        builder.setJs(JS_CODE, "js");
         return true;
       }
     };
     registry = new DefaultJsProcessorRegistry(ImmutableList.of(processor));
     control.replay();
     registry.process(request, response);
-    assertEquals(JS_CODE, response.getJsCode().toString());
+    assertEquals(JS_CODE, response.build().getJsCode());
     control.verify();
   }
 

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=1082977&r1=1082976&r2=1082977&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 Mar 18 17:16:11 2011
@@ -21,7 +21,6 @@ package org.apache.shindig.gadgets.js;
 import static org.junit.Assert.*;
 
 import org.apache.shindig.gadgets.servlet.JsHandler;
-import org.apache.shindig.gadgets.servlet.JsHandler.Response;
 import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
 import org.apache.shindig.gadgets.uri.UriStatus;
 import org.easymock.EasyMock;
@@ -29,6 +28,8 @@ import org.easymock.IMocksControl;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.google.common.collect.ImmutableList;
+
 
 /**
  * Tests for {@link GetJsContentProcessor}.
@@ -42,7 +43,7 @@ public class GetJsContentProcessorTest {
   private JsHandler handler;
   private JsUri jsUri;
   private JsRequest request;
-  private Response handlerResponse;
+  private JsResponse handlerResponse;
   private JsResponseBuilder response;
   private GetJsContentProcessor processor;
 
@@ -52,7 +53,7 @@ public class GetJsContentProcessorTest {
     handler = control.createMock(JsHandler.class);
     jsUri = control.createMock(JsUri.class);
     request = control.createMock(JsRequest.class);
-    handlerResponse = control.createMock(JsHandler.Response.class);
+    handlerResponse = control.createMock(JsResponse.class);
     response = new JsResponseBuilder();
     processor = new GetJsContentProcessor(handler);
   }
@@ -93,11 +94,12 @@ public class GetJsContentProcessorTest {
     control.verify();
   }
 
-  private void setExpectations(boolean proxyCacheable, UriStatus uriStatus) {
+  private void setExpectations(boolean proxyCacheable, UriStatus uriStatus) throws JsException {
     EasyMock.expect(handler.getJsContent(jsUri, HOST)).andReturn(handlerResponse);
     EasyMock.expect(request.getHost()).andReturn(HOST);
     EasyMock.expect(request.getJsUri()).andReturn(jsUri);
-    EasyMock.expect(handlerResponse.getJsData()).andReturn(new StringBuilder(JS_CODE));
+    EasyMock.expect(handlerResponse.allJs()).andReturn(
+        ImmutableList.of(new JsContent(JS_CODE, "source", "feature")));
     EasyMock.expect(handlerResponse.isProxyCacheable()).andReturn(proxyCacheable);
     EasyMock.expect(jsUri.getStatus()).andReturn(uriStatus);
   }
@@ -105,6 +107,6 @@ public class GetJsContentProcessorTest {
   private void checkResponse(boolean proxyCacheable, int expectedTtl) {
     assertEquals(proxyCacheable, response.isProxyCacheable());
     assertEquals(expectedTtl, response.getCacheTtlSecs());
-    assertEquals(JS_CODE, response.getJsCode().toString());
+    assertEquals(JS_CODE, response.build().getJsCode());
   }
 }

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessorTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessorTest.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessorTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/InjectJsInfoVariableProcessorTest.java Fri Mar 18 17:16:11 2011
@@ -78,7 +78,7 @@ public class InjectJsInfoVariableProcess
     control.replay();
     processor.process(request, response);
     String expected = String.format(InjectJsInfoVariableProcessor.HINT_TEMPLATE, URI_JS, LIBS_JS);
-    assertEquals(expected, response.getJsCode().toString());
+    assertEquals(expected, response.build().getJsCode());
     control.verify();    
   }
 
@@ -90,7 +90,7 @@ public class InjectJsInfoVariableProcess
     control.replay();
     processor.process(request, response);
     String expected = String.format(InjectJsInfoVariableProcessor.HINT_TEMPLATE, GENERATED_URI_JS, LIBS_JS);
-    assertEquals(expected, response.getJsCode().toString());
+    assertEquals(expected, response.build().getJsCode());
     assertFalse(captureJsUri.getValue().isJsload());
     assertTrue(captureJsUri.getValue().isNohint());
     control.verify();    

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/JsLoadProcessorTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/JsLoadProcessorTest.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/JsLoadProcessorTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/js/JsLoadProcessorTest.java Fri Mar 18 17:16:11 2011
@@ -124,7 +124,7 @@ public class JsLoadProcessorTest {
     assertEquals(HttpServletResponse.SC_OK, response.getStatusCode());
     assertEquals(expectedTtl, response.getCacheTtlSecs());
     String expectedBody = String.format(JsLoadProcessor.JSLOAD_JS_TPL, uri.toString());
-    assertEquals(expectedBody, response.getJsCode().toString());
+    assertEquals(expectedBody, response.build().getJsCode());
   }
 
 }

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingGadgetRewriterTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingGadgetRewriterTest.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingGadgetRewriterTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/render/RenderingGadgetRewriterTest.java Fri Mar 18 17:16:11 2011
@@ -982,11 +982,11 @@ public class RenderingGadgetRewriterTest
   }
 
   private FeatureResource inline(String content, String debugContent) {
-    return new FeatureResource.Simple(content, debugContent);
+    return new FeatureResource.Simple(content, debugContent, "js");
   }
 
   private FeatureResource extern(String content, String debugContent) {
-    return new FeatureResource.Simple(content, debugContent) {
+    return new FeatureResource.Simple(content, debugContent, "js") {
       @Override
       public boolean isExternal() {
         return true;

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/DefaultJsCompilerTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/DefaultJsCompilerTest.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/DefaultJsCompilerTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/DefaultJsCompilerTest.java Fri Mar 18 17:16:11 2011
@@ -21,13 +21,13 @@ import static org.easymock.EasyMock.crea
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
 
 import com.google.common.collect.Lists;
 
 import org.apache.shindig.gadgets.features.FeatureRegistry.FeatureBundle;
 import org.apache.shindig.gadgets.features.FeatureResource;
-import org.apache.shindig.gadgets.rewrite.js.JsCompiler.Result;
+import org.apache.shindig.gadgets.js.JsContent;
+import org.apache.shindig.gadgets.js.JsResponse;
 import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
 import org.junit.Before;
 import org.junit.Test;
@@ -55,11 +55,11 @@ public class DefaultJsCompilerTest {
     FeatureResource extRes = mockResource(true, RESOURCE_URL_DEB, RESOURCE_URL_OPT);
     FeatureResource intRes = mockResource(false, RESOURCE_CONTENT_DEB, RESOURCE_CONTENT_OPT);
     FeatureBundle bundle = mockBundle(Lists.newArrayList(extRes, intRes));
-    String actual = compiler.getJsContent(jsUri, bundle);
+    Iterable<JsContent> actual = compiler.getJsContent(jsUri, bundle);
     assertEquals(
         "document.write('<script src=\"" + RESOURCE_URL_DEB + "\"></script>');\n" +
         RESOURCE_CONTENT_DEB + ";\n",
-        actual);
+        getContent(actual));
   }
 
   @Test
@@ -68,18 +68,18 @@ public class DefaultJsCompilerTest {
     FeatureResource extRes = mockResource(true, RESOURCE_URL_DEB, RESOURCE_URL_OPT);
     FeatureResource intRes = mockResource(false, RESOURCE_CONTENT_DEB, RESOURCE_CONTENT_OPT);
     FeatureBundle bundle = mockBundle(Lists.newArrayList(extRes, intRes));
-    String actual = compiler.getJsContent(jsUri, bundle);
+    Iterable<JsContent> actual = compiler.getJsContent(jsUri, bundle);
     assertEquals(
         "document.write('<script src=\"" + RESOURCE_URL_OPT + "\"></script>');\n" +
         RESOURCE_CONTENT_OPT + ";\n",
-        actual);
+        getContent(actual));
   }
 
   @Test
   public void testCompile() throws Exception {
-    Result actual = compiler.compile(null, COMPILE_CONTENT, null);
-    assertEquals(COMPILE_CONTENT, actual.getCode());
-    assertNull(actual.getErrors());
+    JsResponse actual = compiler.compile(null, COMPILE_CONTENT, null);
+    assertEquals(COMPILE_CONTENT, actual.getJsCode());
+    assertEquals(0, actual.getErrors().size());
   }
 
   private JsUri mockJsUri(boolean debug) {
@@ -92,6 +92,7 @@ public class DefaultJsCompilerTest {
   private FeatureBundle mockBundle(List<FeatureResource> resources) {
     FeatureBundle result = createMock(FeatureBundle.class);
     expect(result.getResources()).andReturn(resources).anyTimes();
+    expect(result.getName()).andReturn("feature").anyTimes();
     replay(result);
     return result;
   }
@@ -101,7 +102,16 @@ public class DefaultJsCompilerTest {
     expect(result.getDebugContent()).andReturn(debContent).anyTimes();
     expect(result.getContent()).andReturn(optContent).anyTimes();
     expect(result.isExternal()).andReturn(external).anyTimes();
+    expect(result.getName()).andReturn("source").anyTimes();
     replay(result);
     return result;
   }
+  
+  private String getContent(Iterable<JsContent> jsContent) {
+    StringBuilder sb = new StringBuilder();
+    for (JsContent js : jsContent) {
+      sb.append(js.get());
+    }
+    return sb.toString();
+  }
 }

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompilerTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompilerTest.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompilerTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompilerTest.java Fri Mar 18 17:16:11 2011
@@ -34,7 +34,8 @@ import org.apache.shindig.gadgets.featur
 import org.apache.shindig.gadgets.features.FeatureRegistry.FeatureBundle;
 import org.apache.shindig.gadgets.features.FeatureRegistry.LookupResult;
 import org.apache.shindig.gadgets.features.FeatureResource;
-import org.apache.shindig.gadgets.rewrite.js.JsCompiler.Result;
+import org.apache.shindig.gadgets.js.JsContent;
+import org.apache.shindig.gadgets.js.JsResponse;
 import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
 import org.easymock.EasyMock;
 import org.junit.Before;
@@ -109,6 +110,7 @@ public class ExportJsCompilerTest {
     expect(result.getDebugContent()).andReturn(debContent).anyTimes();
     expect(result.getContent()).andReturn(optContent).anyTimes();
     expect(result.isExternal()).andReturn(external).anyTimes();
+    expect(result.getName()).andReturn("js").anyTimes();
     replay(result);
     return result;
   }
@@ -139,11 +141,11 @@ public class ExportJsCompilerTest {
   public void testGetJsContentEmpty() throws Exception {
     JsUri jsUri = mockJsUri(JsCompileMode.ALL_RUN_TIME);
     FeatureBundle bundle = mockBundle(Lists.<FeatureResource>newArrayList(), EMPTY, EMPTY); // empty
-    String actual = compiler.getJsContent(jsUri, bundle);
+    Iterable<JsContent> actual = compiler.getJsContent(jsUri, bundle);
     assertEquals(
-        "\n/* feature=" + RESOURCE_NAME + " */\n" +
-        "\n/* feature=" + RESOURCE_NAME + " */\n",
-        actual);
+        "\n/* [start] feature=" + RESOURCE_NAME + " */\n" +
+        "\n/* [end] feature=" + RESOURCE_NAME + " */\n",
+        getContent(actual));
   }
 
   @Test
@@ -152,30 +154,38 @@ public class ExportJsCompilerTest {
     FeatureResource extRes = mockResource(true, RESOURCE_URL_DEB, RESOURCE_URL_OPT);
     FeatureResource intRes = mockResource(false, RESOURCE_CONTENT_DEB, RESOURCE_CONTENT_OPT);
     FeatureBundle bundle = mockBundle(Lists.newArrayList(extRes, intRes), EXPORTS, EXTERNS);
-    String actual = compiler.getJsContent(jsUri, bundle);
+    Iterable<JsContent> actual = compiler.getJsContent(jsUri, bundle);
     assertEquals(
-        "\n/* feature=" + RESOURCE_NAME + " */\n" +
+        "\n/* [start] feature=" + RESOURCE_NAME + " */\n" +
         "document.write('<script src=\"" + RESOURCE_URL_DEB + "\"></script>');\n" +
         RESOURCE_CONTENT_DEB + ";\n" +
         "exportJs('gadgets',[gadgets]);" +
         "exportJs('cc',[cc]);" +
         "exportJs('gadgets.rpc',[gadgets,gadgets.rpc],{call:'call'});" +
         "exportJs('cc.prototype',[cc,cc.prototype],{site:'site'});" +
-        "\n/* feature=" + RESOURCE_NAME + " */\n",
-        actual);
+        "\n/* [end] feature=" + RESOURCE_NAME + " */\n",
+        getContent(actual));
   }
 
   @Test
   public void testCompileNotEmpty() throws Exception {
     JsUri jsUri = mockJsUri(JsCompileMode.ALL_RUN_TIME);
-    Result actual = compiler.compile(jsUri, COMPILE_CONTENT, EXTERNS);
-    assertEquals(EXPORT_JS_DEB + COMPILE_CONTENT, actual.getCode());
+    JsResponse actual = compiler.compile(jsUri, COMPILE_CONTENT, EXTERNS);
+    assertEquals(EXPORT_JS_DEB + COMPILE_CONTENT, actual.getJsCode());
   }
 
   @Test
   public void testCompileEmpty() throws Exception {
     JsUri jsUri = mockJsUri(JsCompileMode.ALL_RUN_TIME);
-    Result actual = compiler.compile(jsUri, "", EXTERNS);
-    assertEquals(EXPORT_JS_DEB, actual.getCode());
+    JsResponse actual = compiler.compile(jsUri, "", EXTERNS);
+    assertEquals(EXPORT_JS_DEB, actual.getJsCode());
+  }
+  
+  private String getContent(Iterable<JsContent> jsContent) {
+    StringBuilder sb = new StringBuilder();
+    for (JsContent js : jsContent) {
+      sb.append(js.get());
+    }
+    return sb.toString();
   }
 }

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerServiceTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerServiceTest.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerServiceTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerServiceTest.java Fri Mar 18 17:16:11 2011
@@ -39,6 +39,8 @@ import org.apache.shindig.gadgets.Gadget
 import org.apache.shindig.gadgets.features.FeatureRegistry;
 import org.apache.shindig.gadgets.http.HttpResponse;
 import org.apache.shindig.gadgets.http.HttpResponseBuilder;
+import org.apache.shindig.gadgets.js.JsException;
+import org.apache.shindig.gadgets.js.JsResponseBuilder;
 import org.apache.shindig.gadgets.process.ProcessingException;
 import org.apache.shindig.gadgets.uri.JsUriManager;
 import org.apache.shindig.gadgets.uri.ProxyUriManager;
@@ -150,8 +152,7 @@ public class GadgetsHandlerServiceTest e
         FakeProcessor.SPEC_URL3, CONTAINER, "invalid_view",
         createAuthContext(null, null), ImmutableList.of("*"));
     replay();
-    GadgetsHandlerApi.MetadataResponse response =
-        gadgetHandler.getMetadata(request);
+    gadgetHandler.getMetadata(request);
   }
 
   @Test(expected = ProcessingException.class)
@@ -160,7 +161,7 @@ public class GadgetsHandlerServiceTest e
         FakeProcessor.SPEC_URL, null, null,
         createAuthContext(null, null), ImmutableList.of("*"));
     replay();
-    GadgetsHandlerApi.BaseResponse response = gadgetHandler.getMetadata(request);
+    gadgetHandler.getMetadata(request);
   }
 
   @Test(expected = ProcessingException.class)
@@ -169,8 +170,7 @@ public class GadgetsHandlerServiceTest e
         null, CONTAINER, null,
         createAuthContext(null, null), ImmutableList.of("*"));
     replay();
-    GadgetsHandlerApi.MetadataResponse response =
-        gadgetHandler.getMetadata(request);
+    gadgetHandler.getMetadata(request);
   }
 
   @Test(expected = ProcessingException.class)
@@ -179,7 +179,7 @@ public class GadgetsHandlerServiceTest e
         FakeProcessor.SPEC_URL, CONTAINER, null,
         createAuthContext(null, null), null);
     replay();
-    GadgetsHandlerApi.MetadataResponse response = gadgetHandler.getMetadata(request);
+    gadgetHandler.getMetadata(request);
   }
 
   @Test(expected = ProcessingException.class)
@@ -188,7 +188,7 @@ public class GadgetsHandlerServiceTest e
         Uri.parse("unknown"), CONTAINER, null,
         createAuthContext(null, null), null);
     replay();
-    GadgetsHandlerApi.MetadataResponse response = gadgetHandler.getMetadata(request);
+    gadgetHandler.getMetadata(request);
   }
 
   @SuppressWarnings("unchecked")
@@ -228,7 +228,7 @@ public class GadgetsHandlerServiceTest e
         FakeProcessor.SPEC_URL, null,
         createAuthContext(OWNER, VIEWER), ImmutableList.of("*"));
     replay();
-    GadgetsHandlerApi.TokenResponse response = gadgetHandler.getToken(request);
+    gadgetHandler.getToken(request);
   }
 
   @Test(expected = ProcessingException.class)
@@ -237,7 +237,7 @@ public class GadgetsHandlerServiceTest e
         null, CONTAINER,
         createAuthContext(OWNER, VIEWER), ImmutableList.of("*"));
     replay();
-    GadgetsHandlerApi.TokenResponse response = gadgetHandler.getToken(request);
+    gadgetHandler.getToken(request);
   }
 
   @Test(expected = ProcessingException.class)
@@ -246,7 +246,7 @@ public class GadgetsHandlerServiceTest e
         FakeProcessor.SPEC_URL, CONTAINER,
         createAuthContext(OWNER, VIEWER), null);
     replay();
-    GadgetsHandlerApi.TokenResponse response = gadgetHandler.getToken(request);
+    gadgetHandler.getToken(request);
   }
 
   @Test(expected = SecurityTokenException.class)
@@ -256,7 +256,7 @@ public class GadgetsHandlerServiceTest e
         createAuthContext(OWNER, VIEWER), ImmutableList.of("*"));
     replay();
     tokenCodec.exc = new SecurityTokenException("bad data");
-    GadgetsHandlerApi.TokenResponse response = gadgetHandler.getToken(request);
+    gadgetHandler.getToken(request);
   }
 
   @Test
@@ -307,7 +307,7 @@ public class GadgetsHandlerServiceTest e
     List<String> fields = ImmutableList.of("*");
     GadgetsHandlerApi.JsRequest request =
         createJsRequest(null, null, fields, ImmutableList.of("rpc"));
-    GadgetsHandlerApi.JsResponse response = gadgetHandler.getJs(request);
+    gadgetHandler.getJs(request);
   }
 
   @Test
@@ -320,7 +320,7 @@ public class GadgetsHandlerServiceTest e
     String onload = "do this";
     expect(jsUriManager.makeExternJsUri(capture(uriCapture))).andReturn(resUri);
     expect(jsHandler.getJsContent(EasyMock.isA(JsUri.class), EasyMock.eq("server.com")))
-        .andReturn(new JsHandler.Response(new StringBuilder(jsContent), true));
+        .andReturn(new JsResponseBuilder().appendJs(jsContent, "js").setProxyCacheable(true).build());
     GadgetsHandlerApi.JsRequest request =
         createJsRequest(FakeProcessor.SPEC_URL.toString(), CONTAINER, fields, features);
     expect(request.getOnload()).andStubReturn(onload);
@@ -337,6 +337,24 @@ public class GadgetsHandlerServiceTest e
         response.getExpireTimeMs().longValue());
     verify();
   }
+  
+  @Test(expected = ProcessingException.class)
+  public void testGetJsDataWithException() throws Exception {
+    List<String> fields = ImmutableList.of("jscontent");
+    List<String> features = ImmutableList.of("unknown");
+    Uri resUri = Uri.parse("http://server.com/gadgets/js/foo");
+    Capture<JsUri> uriCapture = new Capture<JsUri>();
+    expect(jsUriManager.makeExternJsUri(capture(uriCapture))).andReturn(resUri);
+    expect(jsHandler.getJsContent(EasyMock.isA(JsUri.class), EasyMock.eq("server.com")))
+        .andThrow(new JsException(404, "error"));
+    GadgetsHandlerApi.JsRequest request =
+        createJsRequest(FakeProcessor.SPEC_URL.toString(), CONTAINER, fields, features);
+    expect(request.getOnload()).andStubReturn("do this");
+    expect(request.getContext()).andStubReturn(GadgetsHandlerApi.RenderingContext.CONTAINER);
+    replay();
+
+    gadgetHandler.getJs(request);
+  }
 
   @Test
   public void testCreateProxyUri() throws Exception {
@@ -429,20 +447,20 @@ public class GadgetsHandlerServiceTest e
   public void testGetProxyNoContainer() throws Exception {
     List<String> fields = ImmutableList.of("*");
     GadgetsHandlerApi.ProxyRequest request = createProxyRequest(RESOURCE, null, fields);
-    GadgetsHandlerApi.ProxyResponse response = gadgetHandler.getProxy(request);
+    gadgetHandler.getProxy(request);
   }
 
   @Test(expected = ProcessingException.class)
   public void testGetProxyNoResource() throws Exception {
     List<String> fields = ImmutableList.of("*");
     GadgetsHandlerApi.ProxyRequest request = createProxyRequest(null, CONTAINER, fields);
-    GadgetsHandlerApi.ProxyResponse response = gadgetHandler.getProxy(request);
+    gadgetHandler.getProxy(request);
   }
 
   @Test(expected = ProcessingException.class)
   public void testGetProxyNoFields() throws Exception {
     GadgetsHandlerApi.ProxyRequest request = createProxyRequest(RESOURCE, CONTAINER, null);
-    GadgetsHandlerApi.ProxyResponse response = gadgetHandler.getProxy(request);
+    gadgetHandler.getProxy(request);
   }
 
   @Test
@@ -495,11 +513,11 @@ public class GadgetsHandlerServiceTest e
     Capture<List<ProxyUri>> uriCapture = new Capture<List<ProxyUri>>();
     expect(proxyUriManager.make(capture(uriCapture), EasyMock.anyInt()))
         .andReturn(ImmutableList.of(resUri));
-    HttpResponse httpResponse = new HttpResponse("response");
+    new HttpResponse("response");
     expect(proxyHandler.fetch(EasyMock.isA(ProxyUri.class)))
         .andThrow(new GadgetException(Code.FAILED_TO_RETRIEVE_CONTENT));
     replay();
-    GadgetsHandlerApi.ProxyResponse response = gadgetHandler.getProxy(request);
+    gadgetHandler.getProxy(request);
   }
 
   @Test

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java Fri Mar 18 17:16:11 2011
@@ -36,6 +36,8 @@ import org.apache.shindig.common.uri.Uri
 import org.apache.shindig.common.util.FakeTimeSource;
 import org.apache.shindig.gadgets.RenderingContext;
 import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.js.JsException;
+import org.apache.shindig.gadgets.js.JsResponseBuilder;
 import org.apache.shindig.gadgets.process.ProcessingException;
 import org.apache.shindig.gadgets.servlet.CajaContentRewriter.CajoledResult;
 import org.apache.shindig.gadgets.spec.GadgetSpec;
@@ -153,7 +155,7 @@ public class GadgetsHandlerTest extends 
     JSONObject request = makeMetadataNoContainerRequest(GADGET1_URL);
     RpcHandler operation = registry.getRpcHandler(request);
     try {
-      Object empty = operation.execute(emptyFormItems, authContext, converter).get();
+      operation.execute(emptyFormItems, authContext, converter).get();
       fail("Missing container");
     } catch (Exception e) {
       assertTrue(e.getMessage().contains("Missing container"));
@@ -190,7 +192,7 @@ public class GadgetsHandlerTest extends 
     InputSource is = new InputSource(uri.toJavaUri());
     MessageQueue mq = new SimpleMessageQueue();
     CharProducer cp = CharProducer.Factory.create(new StringReader(content), is);
-    return rw.rewrite(uri, CONTAINER, rw.parse(is, cp, mime, mq), false, false);
+    return rw.rewrite(uri, CONTAINER, CajaContentRewriter.parse(is, cp, mime, mq), false, false);
   }
 
   @Test
@@ -599,7 +601,7 @@ public class GadgetsHandlerTest extends 
     String jsContent = "var b=\"123\";";
     EasyMock.expect(jsHandler.getJsContent(
         EasyMock.isA(JsUri.class), EasyMock.eq(jsUri.getAuthority())))
-        .andReturn(new JsHandler.Response(new StringBuilder(jsContent), true));
+        .andReturn(new JsResponseBuilder().appendJs(jsContent, "js").build());
     replay();
 
     RpcHandler operation = registry.getRpcHandler(request);
@@ -629,7 +631,7 @@ public class GadgetsHandlerTest extends 
         .andReturn(jsUri);
     EasyMock.expect(jsHandler.getJsContent(
         EasyMock.isA(JsUri.class), EasyMock.eq(jsUri.getAuthority())))
-        .andReturn(new JsHandler.Response(new StringBuilder(""), true));
+        .andThrow(new JsException(404, "not found"));
     replay();
 
     RpcHandler operation = registry.getRpcHandler(request);

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/JsServletTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/JsServletTest.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/JsServletTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/JsServletTest.java Fri Mar 18 17:16:11 2011
@@ -36,6 +36,8 @@ import org.apache.shindig.gadgets.js.JsL
 import org.apache.shindig.gadgets.js.JsProcessor;
 import org.apache.shindig.gadgets.js.JsProcessorRegistry;
 import org.apache.shindig.gadgets.js.JsRequestBuilder;
+import org.apache.shindig.gadgets.js.JsResponse;
+import org.apache.shindig.gadgets.js.JsResponseBuilder;
 import org.apache.shindig.gadgets.uri.JsUriManager;
 import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
 import org.apache.shindig.gadgets.uri.UriStatus;
@@ -132,7 +134,7 @@ public class JsServletTest extends Servl
         null, REFRESH_INTERVAL_SEC, UriStatus.VALID_UNVERSIONED);
     expect(jsUriManagerMock.processExternJsUri(isA(Uri.class))).andReturn(jsUri);
     expect(request.getHeader("If-Modified-Since")).andReturn("12345");
-    JsHandler.Response response = new JsHandler.Response(new StringBuilder(EXAMPLE_JS_CODE), true);
+    JsResponse response = new JsResponseBuilder().appendJs(EXAMPLE_JS_CODE, "js").build();
     expect(request.getHeader("Host")).andReturn("localhost");
     expect(jsHandlerMock.getJsContent(jsUri, "localhost")).andReturn(response);
     replay();
@@ -144,7 +146,6 @@ public class JsServletTest extends Servl
   }
   
   @Test
-  @SuppressWarnings("unchecked")
   public void testDoJsloadNormal() throws Exception {
     String url = "http://localhost/gadgets/js/feature.js?v=abc&nocache=0&onload=" + ONLOAD_PARAM;
     JsUri jsUri = mockJsUri(CONTAINER_PARAM, RenderingContext.CONTAINER, true, true, false,

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ModuleCacheTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ModuleCacheTest.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ModuleCacheTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ModuleCacheTest.java Fri Mar 18 17:16:11 2011
@@ -25,12 +25,9 @@ import com.google.caja.reporting.Echoing
 import com.google.caja.reporting.MessageContext;
 import com.google.caja.reporting.MessageQueue;
 import com.google.caja.util.ContentType;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
 
 import java.io.PrintWriter;
 import java.net.URI;
-import java.util.Set;
 
 import junit.framework.TestCase;
 

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/tags/FlashTagHandlerTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/tags/FlashTagHandlerTest.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/tags/FlashTagHandlerTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/tags/FlashTagHandlerTest.java Fri Mar 18 17:16:11 2011
@@ -108,6 +108,10 @@ public class FlashTagHandlerTest extends
     public String getDebugContent() {
       return "swfobject";
     }
+    
+    public String getName() {
+      return "swfname";
+    }
   }
 
   private void expectSecurityToken() {

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/uri/AllJsIframeVersionerTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/uri/AllJsIframeVersionerTest.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/uri/AllJsIframeVersionerTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/uri/AllJsIframeVersionerTest.java Fri Mar 18 17:16:11 2011
@@ -51,7 +51,7 @@ public class AllJsIframeVersionerTest {
     String debugContent = "FEATURE_DEBUG_CONTENT";
     featureChecksum = HashUtil.checksum((featureContent + debugContent).getBytes());
     FeatureRegistry registry = createMock(FeatureRegistry.class);
-    FeatureResource resource = new FeatureResource.Simple(featureContent, debugContent);
+    FeatureResource resource = new FeatureResource.Simple(featureContent, debugContent, "js");
     List<FeatureResource> allResources = Lists.newArrayList(resource);
     final FeatureRegistry.LookupResult lr = createMock(FeatureRegistry.LookupResult.class);
     expect(lr.getResources()).andReturn(allResources);

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/uri/DefaultJsVersionerTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/uri/DefaultJsVersionerTest.java?rev=1082977&r1=1082976&r2=1082977&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/uri/DefaultJsVersionerTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/uri/DefaultJsVersionerTest.java Fri Mar 18 17:16:11 2011
@@ -143,7 +143,7 @@ public class DefaultJsVersionerTest {
   }
 
   private void expectReq(String feature, String content) {
-    FeatureResource resource = new FeatureResource.Simple(content, "");
+    FeatureResource resource = new FeatureResource.Simple(content, "", "js");
     Collection<String> libs = Lists.newArrayList(feature);
     List<FeatureResource> resources = Lists.newArrayList(resource);
     final FeatureRegistry.LookupResult lr = createMock(FeatureRegistry.LookupResult.class);