shindig-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mherma...@apache.org
Subject svn commit: r1080785 - in /shindig/trunk/java/gadgets/src: main/java/org/apache/shindig/gadgets/features/ main/java/org/apache/shindig/gadgets/rewrite/js/ main/java/org/apache/shindig/gadgets/servlet/ test/java/org/apache/shindig/gadgets/rewrite/js/
Date Fri, 11 Mar 2011 22:21:59 GMT
Author: mhermanto
Date: Fri Mar 11 22:21:58 2011
New Revision: 1080785

URL: http://svn.apache.org/viewvc?rev=1080785&view=rev
Log:
Wrap debug JS, exportJs'ed public APIs, re-factor JS compilers to DefaultJsCompiler and ExportJsCompiler.
Respectively, they are for build-time and run-time compile. The later is incomplete (ie: need
to plug in the actual JS compiler). This change paves way for system-wide runtime compilation,
which will initially 1) avoid global namespace pollution, and 2) while public APIs are allowed
to escape (and made available) to global via exportJs. Tests also added.

http://codereview.appspot.com/4266054/

Added:
    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
      - copied, changed from r1076923, shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/AbstractJsCompiler.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
      - copied, changed from r1076923, shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/AbstractJsCompilerTest.java
Removed:
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/AbstractJsCompiler.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/AbstractJsCompilerTest.java
Modified:
    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/rewrite/js/JsCompiler.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsHandler.java

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=1080785&r1=1080784&r2=1080785&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 11 22:21:58 2011
@@ -39,6 +39,7 @@ 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;
@@ -100,7 +101,7 @@ public class FeatureRegistry {
     // Connect the dependency graph made up of all features and validate there
     // are no circular deps.
     connectDependencyGraph();
-    
+
     this.cache = cacheProvider.createCache(CACHE_NAME);
   }
 
@@ -480,7 +481,7 @@ public class FeatureRegistry {
     featureMapBuilder.put(parsed.getName(),
         new FeatureNode(parsed.getName(), bundles, parsed.getDeps()));
   }
-  
+
   protected String makeCacheKey(Collection<String> needed, GadgetContext ctx, List<String>
unsupported) {
     List<String> neededList = Lists.newArrayList(needed);
     Collections.sort(neededList);
@@ -538,7 +539,7 @@ public class FeatureRegistry {
     }
   }
 
-  public static final class FeatureBundle {
+  public static class FeatureBundle {
     private final FeatureParser.ParsedFeature.Bundle bundle;
     private final List<FeatureResource> resources;
 
@@ -567,6 +568,16 @@ public class FeatureRegistry {
     public List<ApiDirective> getApis() {
       return bundle.getApis();
     }
+
+    public List<String> getApis(ApiDirective.Type type, boolean isExports) {
+      ImmutableList.Builder<String> builder = ImmutableList.builder();
+      for (ApiDirective api : bundle.getApis()) {
+        if (api.getType() == type && api.isExports() == isExports) {
+          builder.add(api.getValue());
+        }
+      }
+      return builder.build();
+    }
   }
 
   private static final class FeatureNode {
@@ -606,15 +617,15 @@ public class FeatureRegistry {
         tagMatch = RenderingContext.ALL.getFeatureBundleTag();
       }
       final String useForMatching = tagMatch;
-      
+
       // Return an Iterator rather than coping a new
       // list containing the types over which to iterate.
       return new Iterable<FeatureBundle>() {
         public Iterator<FeatureBundle> iterator() {
           return new Iterator<FeatureBundle>() {
             private FeatureBundle next;
-            private Iterator<FeatureBundle> it = bundles.iterator();
-            
+            private final Iterator<FeatureBundle> it = bundles.iterator();
+
             public boolean hasNext() {
               while (next == null && it.hasNext()) {
                 FeatureBundle candidate = it.next();

Added: 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=1080785&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/DefaultJsCompiler.java
(added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/DefaultJsCompiler.java
Fri Mar 11 22:21:58 2011
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package org.apache.shindig.gadgets.rewrite.js;
+
+import org.apache.shindig.gadgets.features.FeatureRegistry.FeatureBundle;
+import org.apache.shindig.gadgets.features.FeatureResource;
+import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
+
+import java.util.List;
+
+/**
+ * Base for a JsCompiler implementation.
+ */
+public class DefaultJsCompiler implements JsCompiler {
+
+  public String getJsContent(JsUri jsUri, FeatureBundle bundle) {
+    StringBuilder builder = new StringBuilder();
+    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>')");
+      } else {
+        builder.append(content);
+      }
+      builder.append(";\n");
+    }
+    return builder.toString();
+  }
+
+  public Result compile(JsUri jsUri, String content, List<String> externs) {
+    return new Result(content);
+  }
+
+  protected String getFeatureContent(JsUri jsUri, FeatureResource resource) {
+    return jsUri.isDebug() ? resource.getDebugContent() : resource.getContent();
+  }
+}

Copied: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompiler.java
(from r1076923, shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/AbstractJsCompiler.java)
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompiler.java?p2=shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompiler.java&p1=shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/AbstractJsCompiler.java&r1=1076923&r2=1080785&rev=1080785&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/AbstractJsCompiler.java
(original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompiler.java
Fri Mar 11 22:21:58 2011
@@ -25,72 +25,138 @@ import com.google.common.collect.Maps;
 import com.google.inject.Inject;
 
 import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.gadgets.JsCompileMode;
+import org.apache.shindig.gadgets.RenderingContext;
+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.FeatureRegistry.LookupResult;
 import org.apache.shindig.gadgets.features.FeatureResource;
+import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
 
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
 /**
- * Base for a JsCompiler implementation.
+ * JsCompiler implementation for dynamic (or run-time) feature JS compilation.
  */
-public abstract class AbstractJsCompiler implements JsCompiler {
+public class ExportJsCompiler extends DefaultJsCompiler {
 
   @VisibleForTesting
   static final String FEATURE_NAME = "exportjs";
 
   private static final String FUNCTION_NAME = "exportJs";
 
-  private boolean hasInjectedJs = false;
   private final FeatureRegistry featureRegistry;
 
   @Inject
-  public AbstractJsCompiler(FeatureRegistry featureRegistry) {
+  public ExportJsCompiler(FeatureRegistry featureRegistry) {
     this.featureRegistry = featureRegistry;
   }
 
-  private void appendExportJsFeature(StringBuilder out, GadgetContext context) {
-    LookupResult lookup = featureRegistry.getFeatureResources(context,
-        ImmutableList.of(FEATURE_NAME), null);
-    for (FeatureRegistry.FeatureBundle bundle : lookup.getBundles()) {
-      for (FeatureResource resource : bundle.getResources()) {
-        out.append(resource.getDebugContent());
+  @Override
+  public String getJsContent(JsUri jsUri, FeatureBundle bundle) {
+    StringBuilder builder = new StringBuilder();
+    builder.append("\n/* feature=").append(bundle.getName()).append(" */\n");
+    builder.append("(function() {");
+    builder.append(super.getJsContent(jsUri, bundle));
+    appendExportsForFeature(builder, jsUri, bundle);
+    builder.append("})();");
+    builder.append("\n/* feature=").append(bundle.getName()).append(" */\n");
+    return builder.toString();
+  }
+
+  @Override
+  public Result compile(JsUri jsUri, String content, List<String> externs) {
+    GadgetContext ctx = new JsGadgetContext(jsUri);
+    StringBuilder builder = new StringBuilder();
+    builder.append(getExportJsFeature(ctx));
+    builder.append(content);
+    return new Result(builder.toString());
+  }
+
+  @Override
+  protected String getFeatureContent(JsUri jsUri, FeatureResource resource) {
+    return resource.getDebugContent();
+  }
+
+  private void appendExportsForFeature(StringBuilder out, JsUri jsUri, FeatureBundle bundle)
{
+    List<String> exports = Lists.newArrayList();
+
+    // Add exports of bundle, regardless.
+    if (jsUri.getCompileMode() == JsCompileMode.ALL_RUN_TIME) {
+      exports = bundle.getApis(ApiDirective.Type.JS, true);
+
+    // Add exports of bundle if it is an explicitly-specified feature.
+    } else if (jsUri.getCompileMode() == JsCompileMode.EXPLICIT_RUN_TIME) {
+      if (jsUri.getLibs().contains(bundle.getName())) {
+        exports = bundle.getApis(ApiDirective.Type.JS, true);
       }
     }
+
+    for (Input input : generateInputs(exports)) {
+      out.append(input.toExportStatement());
+    }
   }
 
-  public String generateExportStatements(GadgetContext context, List<String> symbols)
{
-    Collection<Input> inputs = generateInputs(symbols);
-    StringBuilder result = new StringBuilder();
-    if (!inputs.isEmpty()) {
-      if (!hasInjectedJs) {
-        appendExportJsFeature(result, context);
-        hasInjectedJs = true;
-      }
-      for (Input input : inputs) {
-        result.append(generateExportStatement(input));
+  private String getExportJsFeature(GadgetContext context) {
+    StringBuilder builder = new StringBuilder();
+    LookupResult lookup = featureRegistry.getFeatureResources(context,
+        ImmutableList.of(FEATURE_NAME), null);
+    for (FeatureBundle bundle : lookup.getBundles()) {
+      for (FeatureResource resource : bundle.getResources()) {
+        builder.append(resource.getDebugContent());
       }
     }
-    return result.toString();
+    return builder.toString();
   }
 
   private static class Input {
     String namespace;
     List<String> components;
     List<String> properties;
+
     private Input(String namespace, List<String> components) {
       this.namespace = namespace;
       this.components = components;
       this.properties = Lists.newArrayList();
     }
+
     static Input newGlobal() {
       return new Input(null, ImmutableList.<String>of());
     }
+
     static Input newLocal(String namespace, List<String> components) {
       return new Input(namespace, components);
     }
+
+    public String toExportStatement() {
+      StringBuilder result = new StringBuilder();
+
+      // Local namespace.
+      if (namespace != null) {
+        result.append(FUNCTION_NAME).append("('").append(namespace).append("',[");
+        result.append(Joiner.on(',').join(components));
+        result.append("],{");
+        for (int i = 0; i < properties.size(); i++) {
+          String prop = properties.get(i);
+          if (i > 0) result.append(",");
+          result.append(prop).append(":'").append(prop).append("'");
+        }
+        result.append("});");
+
+      // Global/window namespace.
+      } else {
+        for (int i = 0; i < properties.size(); i++) {
+          String prop = properties.get(i);
+          result.append(FUNCTION_NAME).append("(");
+          result.append("'").append(prop).append("',[").append(prop);
+          result.append("]);");
+        }
+      }
+      return result.toString();
+    }
   }
 
   private List<String> expandNamespace(String namespace) {
@@ -123,34 +189,6 @@ public abstract class AbstractJsCompiler
     return result.values();
   }
 
-  private String generateExportStatement(Input input) {
-    StringBuilder result = new StringBuilder();
-
-    // Local namespace.
-    if (input.namespace != null) {
-      result.append(FUNCTION_NAME).append("('").append(input.namespace).append("',[");
-      result.append(Joiner.on(',').join(input.components));
-      result.append("],{");
-      for (int i = 0; i < input.properties.size(); i++) {
-        String prop = input.properties.get(i);
-        if (i > 0) result.append(",");
-        result.append(prop).append(":'").append(prop).append("'");
-      }
-      result.append("});");
-
-    // Global/window namespace.
-    } else {
-      for (int i = 0; i < input.properties.size(); i++) {
-        String prop = input.properties.get(i);
-        result.append(FUNCTION_NAME).append("(");
-        result.append("'").append(prop).append("',[").append(prop);
-        result.append("]);");
-      }
-    }
-
-    return result.toString();
-  }
-
   /**
    * Return the namespace for symbol (before last dot). If symbol is global,
    * return null, to indicate "window" namespace.
@@ -168,4 +206,24 @@ public abstract class AbstractJsCompiler
     int idx = symbol.lastIndexOf('.');
     return (idx >= 0) ? symbol.substring(idx + 1) : symbol;
   }
+
+  protected static class JsGadgetContext extends GadgetContext {
+    private final RenderingContext renderingContext;
+    private final String container;
+
+    public JsGadgetContext(JsUri ctx) {
+      this.renderingContext = ctx.getContext();
+      this.container = ctx.getContainer();
+    }
+
+    @Override
+    public RenderingContext getRenderingContext() {
+      return renderingContext;
+    }
+
+    @Override
+    public String getContainer() {
+      return container;
+    }
+  }
 }

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=1080785&r1=1080784&r2=1080785&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 11 22:21:58 2011
@@ -17,31 +17,38 @@
  */
 package org.apache.shindig.gadgets.rewrite.js;
 
-import org.apache.shindig.gadgets.GadgetContext;
+import com.google.inject.ImplementedBy;
+
+import org.apache.shindig.gadgets.features.FeatureRegistry.FeatureBundle;
+import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
 
 import java.util.List;
 
+/**
+ * Compiler to pre-process each feature independently and compile a
+ * concatenation of pre-processed data.
+ */
+@ImplementedBy(DefaultJsCompiler.class)
 public interface JsCompiler {
+
   /**
-   * Compiles the provided code with the provided list of external symbols.
-   *
-   * @param jsData The code to compile.
-   * @param externs The list of external symbols.
-   * @return A compilation result object.
+   * Pre-process feature JS.
+   * @param jsUri The JS uri making the request.
+   * @param bundle The feature bundle.
+   * @return Processed feature JS.
    */
-  public Result compile(String jsData, List<String> externs);
+  String getJsContent(JsUri jsUri, FeatureBundle bundle);
 
   /**
-   * Generates a sequence of statements to mark the specified symbols as
-   * exported.
-   *
-   * @param context The gadget context.
-   * @param symbols The symbols to export.
-   * @return A sequence of JavaScript statements to export those symbols.
+   * Compiles the provided code with the provided list of external symbols.
+   * @param jsUri The JS uri making the request.
+   * @param content The raw/pre-processed JS code.
+   * @param externs The externs.
+   * @return A compilation result object.
    */
-  public String generateExportStatements(GadgetContext context, List<String> symbols);
+  Result compile(JsUri jsUri, String content, List<String> externs);
 
-  public static class Result {
+  static class Result {
     private final String compiled;
     private final List<String> errors;
 

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=1080785&r1=1080784&r2=1080785&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 11 22:21:58 2011
@@ -17,10 +17,16 @@
  */
 package org.apache.shindig.gadgets.servlet;
 
+import com.google.caja.util.Sets;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
 import org.apache.shindig.common.JsonSerializer;
 import org.apache.shindig.config.ContainerConfig;
 import org.apache.shindig.gadgets.GadgetContext;
-import org.apache.shindig.gadgets.JsCompileMode;
 import org.apache.shindig.gadgets.RenderingContext;
 import org.apache.shindig.gadgets.config.ConfigContributor;
 import org.apache.shindig.gadgets.features.ApiDirective;
@@ -32,13 +38,8 @@ import org.apache.shindig.gadgets.uri.Js
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-
-import com.google.caja.util.Join;
-import com.google.caja.util.Sets;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 /**
  * Provide processing logic for the JsServlet to serve the JavsScript as features request.
@@ -47,6 +48,7 @@ import com.google.inject.Singleton;
 @Singleton
 public class JsHandler {
   private static final Collection<String> EMPTY_SET = Sets.newHashSet();
+  private static final Logger LOG = Logger.getLogger(JsHandler.class.getName());
 
   protected final FeatureRegistry registry;
   protected final ContainerConfig containerConfig;
@@ -68,13 +70,6 @@ public class JsHandler {
     this.compiler = compiler;
   }
 
-  protected boolean willCompile(JsUri jsUri) {
-    JsCompileMode mode = jsUri.getCompileMode();
-    return (compiler != null) && !jsUri.isDebug() && (
-       mode == JsCompileMode.ALL_RUN_TIME ||
-       mode == JsCompileMode.EXPLICIT_RUN_TIME);
-  }
-
   /**
    * Get the content of the feature resources and push it to jsData.
    *
@@ -85,7 +80,6 @@ public class JsHandler {
   public Response getJsContent(final JsUri jsUri, String host) {
     GadgetContext ctx = new JsGadgetContext(jsUri);
     Collection<String> needed = jsUri.getLibs();
-    String container = ctx.getContainer();
     boolean isProxyCacheable = true;
 
     FeatureRegistry.LookupResult lookup = registry.getFeatureResources(ctx, needed, null);
@@ -93,68 +87,38 @@ public class JsHandler {
     // Quick-and-dirty implementation of incremental JS loading.
     Collection<String> alreadyLoaded = EMPTY_SET;
     Collection<String> alreadyHaveLibs = jsUri.getLoadedLibs();
-    if (alreadyHaveLibs.size() > 0) {
+    if (!alreadyHaveLibs.isEmpty()) {
       alreadyLoaded = registry.getFeatures(alreadyHaveLibs);
     }
 
     // Collate all JS desired for the current request.
-    boolean willCompile = willCompile(jsUri);
     StringBuilder jsData = new StringBuilder();
     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));
+      allExterns.addAll(bundle.getApis(ApiDirective.Type.JS, false));
       for (FeatureResource featureResource : bundle.getResources()) {
-        String content = jsUri.isDebug() || willCompile
-           ? featureResource.getDebugContent() : featureResource.getContent();
-        if (content == null) content = "";
-        if (!featureResource.isExternal()) {
-          jsData.append(content);
-        } else {
-          // Support external/type=url feature serving through document.write()
-          jsData.append("document.write('<script src=\"").append(content).append("\"></script>')");
-        }
         isProxyCacheable = isProxyCacheable && featureResource.isProxyCacheable();
-        jsData.append(";\n");
-      }
-
-      if (willCompile) {
-
-        List<String> rawExports = Lists.newArrayList();
-
-        // Add exports of bundle, regardless.
-        if (jsUri.getCompileMode() == JsCompileMode.ALL_RUN_TIME) {
-          appendExportsForBundle(bundle, rawExports);
-
-        // Add exports of bundle if it is an explicitly-specified feature.
-        } else if (jsUri.getCompileMode() == JsCompileMode.EXPLICIT_RUN_TIME) {
-          if (needed.contains(bundle.getName())) {
-            appendExportsForBundle(bundle, rawExports);
-          }
-        }
-
-        // Add externs for this bundle.
-        appendExternsForBundle(bundle, allExterns);
-
-        jsData.append(compiler.generateExportStatements(ctx, rawExports));
       }
     }
 
-    // Compile if desired. Specific compiler options are provided to the JsCompiler instance.
-    if (willCompile) {
-      StringBuilder compiled = new StringBuilder();
-      JsCompiler.Result result = compiler.compile(jsData.toString(), allExterns);
-      String code = result.getCode();
-      if (code != null) {
-        compiled.append(code);
-        jsData = compiled;
-      } else {
-        System.err.println("JS Compilation error: " + Join.join(", ", result.getErrors()));
-      }
+    // Compile all pre-processed features.
+    JsCompiler.Result result = compiler.compile(jsUri, jsData.toString(), allExterns);
+
+    String code = result.getCode();
+    if (code != null) {
+      jsData = new StringBuilder(code);
+    } else {
+      warn(result);
     }
 
     // Append gadgets.config initialization if not in standard gadget mode.
     if (ctx.getRenderingContext() != RenderingContext.GADGET) {
+      String container = ctx.getContainer();
+
       // Append some container specific things
       Map<String, Object> features = containerConfig.getMap(container, "gadgets.features");
       Map<String, Object> config =
@@ -181,20 +145,9 @@ public class JsHandler {
     return new Response(jsData, isProxyCacheable);
   }
 
-  private void appendExternsForBundle(FeatureRegistry.FeatureBundle bundle, List<String>
externs) {
-    for (ApiDirective api : bundle.getApis()) {
-      if (api.getType() == ApiDirective.Type.JS && api.isUses()) {
-        externs.add(api.getValue());
-      }
-    }
-  }
-
-  private void appendExportsForBundle(FeatureRegistry.FeatureBundle bundle, List<String>
exports) {
-    for (ApiDirective api : bundle.getApis()) {
-      if (api.getType() == ApiDirective.Type.JS && api.isExports()) {
-        exports.add(api.getValue());
-      }
-    }
+  protected void warn(JsCompiler.Result result) {
+    LOG.log(Level.WARNING, "Continuing with un-compiled content. " +
+        "JS Compilation error: " + Joiner.on(", ").join(result.getErrors()));
   }
 
   /**
@@ -224,10 +177,12 @@ public class JsHandler {
   protected static class JsGadgetContext extends GadgetContext {
     private final RenderingContext renderingContext;
     private final String container;
+    private final boolean debug;
 
     public JsGadgetContext(JsUri ctx) {
       this.renderingContext = ctx.getContext();
       this.container = ctx.getContainer();
+      this.debug = ctx.isDebug();
     }
 
     @Override
@@ -239,5 +194,10 @@ public class JsHandler {
     public String getContainer() {
       return container;
     }
+
+    @Override
+    public boolean getDebug() {
+      return debug;
+    }
   }
 }

Added: 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=1080785&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/DefaultJsCompilerTest.java
(added)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/DefaultJsCompilerTest.java
Fri Mar 11 22:21:58 2011
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package org.apache.shindig.gadgets.rewrite.js;
+
+import static org.easymock.EasyMock.createMock;
+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.uri.JsUriManager.JsUri;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+
+
+public class DefaultJsCompilerTest {
+  private final String COMPILE_CONTENT = "alert('compile');";
+  private final String RESOURCE_CONTENT_DEB = "alert('deb');";
+  private final String RESOURCE_CONTENT_OPT = "alert('opt');";
+  private final String RESOURCE_URL_DEB = "deb.js";
+  private final String RESOURCE_URL_OPT = "opt.js";
+
+  private DefaultJsCompiler compiler;
+
+  @Before
+  public void setUp() throws Exception {
+    compiler = new DefaultJsCompiler();
+  }
+
+  @Test
+  public void testGetJsContentWithDeb() throws Exception {
+    JsUri jsUri = mockJsUri(true); // debug
+    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);
+    assertEquals(
+        "document.write('<script src=\"" + RESOURCE_URL_DEB + "\"></script>');\n"
+
+        RESOURCE_CONTENT_DEB + ";\n",
+        actual);
+  }
+
+  @Test
+  public void testGetJsContentWithOpt() throws Exception {
+    JsUri jsUri = mockJsUri(false); // optimized
+    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);
+    assertEquals(
+        "document.write('<script src=\"" + RESOURCE_URL_OPT + "\"></script>');\n"
+
+        RESOURCE_CONTENT_OPT + ";\n",
+        actual);
+  }
+
+  @Test
+  public void testCompile() throws Exception {
+    Result actual = compiler.compile(null, COMPILE_CONTENT, null);
+    assertEquals(COMPILE_CONTENT, actual.getCode());
+    assertNull(actual.getErrors());
+  }
+
+  private JsUri mockJsUri(boolean debug) {
+    JsUri result = createMock(JsUri.class);
+    expect(result.isDebug()).andReturn(debug).anyTimes();
+    replay(result);
+    return result;
+  }
+
+  private FeatureBundle mockBundle(List<FeatureResource> resources) {
+    FeatureBundle result = createMock(FeatureBundle.class);
+    expect(result.getResources()).andReturn(resources).anyTimes();
+    replay(result);
+    return result;
+  }
+
+  private FeatureResource mockResource(boolean external, String debContent, String optContent)
{
+    FeatureResource result = createMock(FeatureResource.class);
+    expect(result.getDebugContent()).andReturn(debContent).anyTimes();
+    expect(result.getContent()).andReturn(optContent).anyTimes();
+    expect(result.isExternal()).andReturn(external).anyTimes();
+    replay(result);
+    return result;
+  }
+}

Copied: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompilerTest.java
(from r1076923, shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/AbstractJsCompilerTest.java)
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompilerTest.java?p2=shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompilerTest.java&p1=shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/AbstractJsCompilerTest.java&r1=1076923&r2=1080785&rev=1080785&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/AbstractJsCompilerTest.java
(original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/js/ExportJsCompilerTest.java
Fri Mar 11 22:21:58 2011
@@ -19,52 +19,84 @@ package org.apache.shindig.gadgets.rewri
 
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.isA;
 import static org.easymock.EasyMock.replay;
 import static org.junit.Assert.assertEquals;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
 
 import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.gadgets.JsCompileMode;
+import org.apache.shindig.gadgets.RenderingContext;
+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.FeatureRegistry.LookupResult;
 import org.apache.shindig.gadgets.features.FeatureResource;
+import org.apache.shindig.gadgets.rewrite.js.JsCompiler.Result;
+import org.apache.shindig.gadgets.uri.JsUriManager.JsUri;
+import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
 
 import java.util.List;
 
-public class AbstractJsCompilerTest {
-  private final String EXPORT_JS_FUNCTION = "function exportJs() { };";
+public class ExportJsCompilerTest {
+  private final String EXPORT_JS_DEB = "function exportJs() { };";
+  private final String EXPORT_JS_OPT = "function a(){};";
+  private final String RESOURCE_NAME = "xyz";
+  private final String RESOURCE_CONTENT_DEB = "alert('deb');";
+  private final String RESOURCE_CONTENT_OPT = "alert('opt');";
+  private final String RESOURCE_URL_DEB = "deb.js";
+  private final String RESOURCE_URL_OPT = "opt.js";
+  private final String COMPILE_CONTENT = "alert('compile');";
+  private final String CONTAINER = "container";
+
+  private final List<String> EMPTY = ImmutableList.of();
+
+  private final List<String> EXPORTS = ImmutableList.of(
+      "gadgets",
+      "gadgets.rpc.call",
+      "cc",
+      "cc.prototype.site");
+
+  private final List<String> EXTERNS = ImmutableList.of(
+      "foo",
+      "foo.bar",
+      "for.prototype.bar");
 
-  private AbstractJsCompiler compiler;
-  private GadgetContext context;
+  private ExportJsCompiler compiler;
 
   @Before
   public void setUp() throws Exception {
-    context = new GadgetContext();
-    FeatureResource featureResourceMock = mockFeatureResource();
+    FeatureResource featureResourceMock = mockResource(true, EXPORT_JS_DEB, EXPORT_JS_OPT);
     FeatureRegistry.FeatureBundle featureBundle = new FeatureRegistry.FeatureBundle(
         null, ImmutableList.of(featureResourceMock));
     LookupResult lookupMock = mockLookupResult(featureBundle);
-    FeatureRegistry featureRegistryMock = mockFeatureRegistry(lookupMock);
-
-    compiler = new AbstractJsCompiler(featureRegistryMock) {
-      public Result compile(String jsData, List<String> externs) {
-        return null;
-      }
-    };
+    FeatureRegistry featureRegistryMock = mockRegistry(lookupMock);
+    compiler = new ExportJsCompiler(featureRegistryMock);
   }
 
   @SuppressWarnings("unchecked")
-  private FeatureRegistry mockFeatureRegistry(LookupResult lookupMock) {
+  private FeatureRegistry mockRegistry(LookupResult lookupMock) {
     FeatureRegistry result = createMock(FeatureRegistry.class);
     expect(result.getFeatureResources(
-        context, ImmutableList.of(AbstractJsCompiler.FEATURE_NAME), null)).
+        isA(GadgetContext.class), isA(List.class), EasyMock.isNull(List.class))).
         andReturn(lookupMock).anyTimes();
     replay(result);
     return result;
   }
 
+  private JsUri mockJsUri(JsCompileMode mode) {
+    JsUri result = createMock(JsUri.class);
+    expect(result.getContext()).andReturn(RenderingContext.GADGET).anyTimes();
+    expect(result.getContainer()).andReturn(CONTAINER).anyTimes();
+    expect(result.getCompileMode()).andReturn(mode).anyTimes();
+    replay(result);
+    return result;
+  }
+
   private LookupResult mockLookupResult(FeatureRegistry.FeatureBundle featureBundle) {
     LookupResult result = createMock(LookupResult.class);
     expect(result.getBundles()).andReturn(ImmutableList.of(featureBundle)).anyTimes();
@@ -72,39 +104,82 @@ public class AbstractJsCompilerTest {
     return result;
   }
 
-  private FeatureResource mockFeatureResource() {
+  private FeatureResource mockResource(boolean external, String debContent, String optContent)
{
     FeatureResource result = createMock(FeatureResource.class);
-    expect(result.getDebugContent()).andReturn(EXPORT_JS_FUNCTION).anyTimes();
+    expect(result.getDebugContent()).andReturn(debContent).anyTimes();
+    expect(result.getContent()).andReturn(optContent).anyTimes();
+    expect(result.isExternal()).andReturn(external).anyTimes();
+    replay(result);
+    return result;
+  }
+
+  private FeatureBundle mockBundle(List<FeatureResource> resources, List<String>
exports, List<String> externs) {
+    List<ApiDirective> apis = Lists.newArrayList();
+    for (String e : exports) apis.add(mockApiDirective(true, e));
+    for (String e : externs) apis.add(mockApiDirective(false, e));
+    FeatureBundle result = createMock(FeatureBundle.class);
+    expect(result.getResources()).andReturn(resources).anyTimes();
+    expect(result.getName()).andReturn(RESOURCE_NAME).anyTimes();
+    expect(result.getApis(ApiDirective.Type.JS, true)).andReturn(exports).anyTimes();
+    expect(result.getApis(ApiDirective.Type.JS, false)).andReturn(externs).anyTimes();
+    replay(result);
+    return result;
+  }
+
+  private ApiDirective mockApiDirective(boolean isExports, String value) {
+    ApiDirective result = createMock(ApiDirective.class);
+    expect(result.getType()).andReturn(ApiDirective.Type.JS).anyTimes();
+    expect(result.getValue()).andReturn(value).anyTimes();
+    expect(result.isExports()).andReturn(isExports).anyTimes();
     replay(result);
     return result;
   }
 
   @Test
-  public void testGenerateExportStatementsEmpty() throws Exception {
-    String actual = compiler.generateExportStatements(context, ImmutableList.<String>of());
-    assertEquals("", actual);
+  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);
+    assertEquals(
+        "\n/* feature=" + RESOURCE_NAME + " */\n" +
+        "(function() {" +
+        "})();" +
+        "\n/* feature=" + RESOURCE_NAME + " */\n",
+        actual);
   }
 
   @Test
-  public void testGenerateExportStatementsNotEmpty() throws Exception {
-    ImmutableList<String> list = ImmutableList.of(
-        "gadgets",
-        "gadgets.rpc.call",
-        "cc",
-        "cc.prototype.site");
-    String actual = compiler.generateExportStatements(context, list);
+  public void testGetJsContentNotEmpty() throws Exception {
+    JsUri jsUri = mockJsUri(JsCompileMode.ALL_RUN_TIME);
+    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);
     assertEquals(
-        EXPORT_JS_FUNCTION +
+        "\n/* feature=" + RESOURCE_NAME + " */\n" +
+        "(function() {" +
+        "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'});",
-        actual);
-    list = ImmutableList.of("gadgets.util.makeClosure");
-    actual = compiler.generateExportStatements(context, list);
-    assertEquals(
-        // JS functions only get inlined once.
-        "exportJs('gadgets.util',[gadgets,gadgets.util],{makeClosure:'makeClosure'});",
+        "exportJs('cc.prototype',[cc,cc.prototype],{site:'site'});" +
+        "})();" +
+        "\n/* feature=" + RESOURCE_NAME + " */\n",
         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());
+  }
+
+  @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());
+  }
 }



Mime
View raw message