You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by et...@apache.org on 2008/02/22 13:36:35 UTC

svn commit: r630176 - in /incubator/shindig/trunk: config/ java/gadgets/src/main/java/org/apache/shindig/gadgets/ java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ java/gadgets/src/main/java/org/apache/shindig/util/ java/gadgets/src/test/java...

Author: etnu
Date: Fri Feb 22 04:36:32 2008
New Revision: 630176

URL: http://svn.apache.org/viewvc?rev=630176&view=rev
Log:
This patch provides:

- The ability to overwrite any feature. This allows you to maintain your own implementation of any feature without having to maintain a patch file or manually copying things over.
- The ability to serve different javascript depending on the syndicator. This allows you to, for example, serve a separate open social javascript file to a production host than you would serve to a testing deployment.
- Simplifies the feature dependency graph. Now the dependencies are just strings, which allows for registering features in any order. Note that the feature graph was never actually validated, and that continues to be the case for now. NEVER register a new feature after you've started rendering gadgets!
- Eliminated the hacky OpenSocialFeatureFactory class, since everything it enabled is satisfied (and more) by the previous changes.


Added:
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/XmlUtil.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsFeatureLoaderTest.java
Removed:
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/OpenSocialFeatureFactory.java
Modified:
    incubator/shindig/trunk/config/syndicator.js
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeatureRegistry.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibraryFeatureFactory.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SyndicatorConfig.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsServlet.java

Modified: incubator/shindig/trunk/config/syndicator.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/config/syndicator.js?rev=630176&r1=630175&r2=630176&view=diff
==============================================================================
--- incubator/shindig/trunk/config/syndicator.js (original)
+++ incubator/shindig/trunk/config/syndicator.js Fri Feb 22 04:36:32 2008
@@ -35,9 +35,6 @@
 // to share configuration.
 {"gadgets.syndicator" : ["default"],
 
-// Location of opensocial-0.7 javascript (loaded server-side).
-"opensocial.0.7.location" : null, // not supported by default. over ride this in
-                                  // your own syndicator file.
 // Set of regular expressions to validate the parent parameter. This is
 // necessary to support situations where you want a single syndicator to support
 // multiple possible host names (such as for localized domains, such as

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeatureRegistry.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeatureRegistry.java?rev=630176&r1=630175&r2=630176&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeatureRegistry.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeatureRegistry.java Fri Feb 22 04:36:32 2008
@@ -17,8 +17,6 @@
  */
 package org.apache.shindig.gadgets;
 
-import org.apache.shindig.util.Check;
-
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -103,7 +101,7 @@
       // Make sure non-core features depend on core.
       for (Entry entry : jsFeatures) {
         if (!entry.name.startsWith("core") && !entry.name.equals("core")) {
-          entry.deps.addAll(core.values());
+          entry.deps.addAll(core.keySet());
         }
       }
 
@@ -129,17 +127,13 @@
    */
   public Entry register(String name, List<String> deps,
                         GadgetFeatureFactory feature) {
-    // Core entries must come first.
-    Entry entry = features.get(name);
-    if (entry == null) {
-      logger.info("Registering feature: " + name + " with deps " + deps);
-      entry = new Entry(name, deps, feature, this);
-      if (coreDone) {
-        entry.deps.addAll(core.values());
-      }
-      features.put(name, entry);
-      validateFeatureGraph();
+    logger.info("Registering feature: " + name + " with deps " + deps);
+    Entry entry = new Entry(name, deps, feature, this);
+    if (coreDone) {
+      entry.deps.addAll(core.keySet());
     }
+    features.put(name, entry);
+    validateFeatureGraph();
     return entry;
   }
 
@@ -213,8 +207,8 @@
    * @param entry
    */
   private void addEntryToSet(Set<Entry> results, Entry entry) {
-    for (Entry dep : entry.deps) {
-      addEntryToSet(results, dep);
+    for (String dep : entry.deps) {
+      addEntryToSet(results, features.get(dep));
     }
     results.add(entry);
   }
@@ -233,8 +227,8 @@
    */
   public static class Entry {
     private final String name;
-    private final Set<Entry> deps;
-    private final Set<Entry> readDeps;
+    private final Set<String> deps;
+    private final Set<String> readDeps;
     private final GadgetFeatureFactory feature;
 
     private Entry(String name,
@@ -243,14 +237,10 @@
                   GadgetFeatureRegistry registry)
         throws IllegalStateException {
       this.name = name;
-      this.deps = new HashSet<Entry>();
+      this.deps = new HashSet<String>();
       this.readDeps = Collections.unmodifiableSet(this.deps);
       if (deps != null) {
-        for (String dep : deps) {
-          Entry entry = registry.getEntry(dep);
-          Check.notNull(entry, "Dependency " + dep + " is not registered.");
-          this.deps.add(entry);
-        }
+        this.deps.addAll(deps);
       }
       this.feature = feature;
     }
@@ -265,7 +255,7 @@
     /**
      * @return List of identifiers on which feature depends
      */
-    public Set<Entry> getDependencies() {
+    public Set<String> getDependencies() {
       return readDeps;
     }
 
@@ -277,8 +267,6 @@
       if (rhs instanceof Entry) {
         Entry entry = (Entry)rhs;
         return name.equals(entry.name);
-      } else if (rhs instanceof String) {
-        return name.equals(rhs);
       }
       return false;
     }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java?rev=630176&r1=630175&r2=630176&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java Fri Feb 22 04:36:32 2008
@@ -399,16 +399,16 @@
         // sanity check: each depends on the spec having been loaded
         prepareDeps.add(specLoadDep);
 
-        for (GadgetFeatureRegistry.Entry featureDep : entry.getDependencies()) {
+        for (String dep : entry.getDependencies()) {
           // prepare depends on all its own deps...
           WorkflowDependency prepareNeedsDep =
               new WorkflowDependency(WorkflowDependency.Type.FEATURE_PREPARE,
-                                     featureDep.getName());
+                                     dep);
           prepareDeps.add(prepareNeedsDep);
 
           WorkflowDependency processNeedsDep =
             new WorkflowDependency(WorkflowDependency.Type.FEATURE_PROCESS,
-                                   featureDep.getName());
+                                   dep);
           // Can't process until all dependencies prepare() and process()
           // have completed.
           processDeps.add(prepareNeedsDep);

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java?rev=630176&r1=630175&r2=630176&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java Fri Feb 22 04:36:32 2008
@@ -18,8 +18,8 @@
 package org.apache.shindig.gadgets;
 
 import org.apache.shindig.util.ResourceLoader;
+import org.apache.shindig.util.XmlUtil;
 import org.w3c.dom.Document;
-import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 import org.xml.sax.InputSource;
@@ -28,7 +28,6 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.StringReader;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -73,35 +72,49 @@
    */
   public Set<GadgetFeatureRegistry.Entry> loadFeatures(String path,
       GadgetFeatureRegistry registry) throws GadgetException {
-    Map<String, ParsedFeature> deps = new HashMap<String, ParsedFeature>();
+    List<ParsedFeature> features = new LinkedList<ParsedFeature>();
     try {
       if (path.startsWith("res://")) {
         path = path.substring(6);
         logger.info("Loading resources from: " + path);
         if (path.endsWith(".txt")) {
-          loadResources(ResourceLoader.getContent(path).split("\n"), deps);
+          loadResources(ResourceLoader.getContent(path).split("\n"), features);
         } else {
-          loadResources(new String[]{path}, deps);
+          loadResources(new String[]{path}, features);
         }
       } else {
         logger.info("Loading files from: " + path);
         File file = new File(path);
-        loadFiles(new File[]{file}, deps);
+        loadFiles(new File[]{file}, features);
       }
     } catch (IOException e) {
       throw new GadgetException(GadgetException.Code.INVALID_PATH, e);
     }
 
-
-
-    // This ensures that we register everything in the right order.
-    Set<GadgetFeatureRegistry.Entry> registered
+    Set<GadgetFeatureRegistry.Entry> entries
         = new HashSet<GadgetFeatureRegistry.Entry>();
-    for (Map.Entry<String, ParsedFeature> entry : deps.entrySet()) {
-      ParsedFeature feature = entry.getValue();
-      register(registry, feature, registered, deps);
+    for (ParsedFeature feature : features) {
+      JsLibraryFeatureFactory factory
+          = new JsLibraryFeatureFactory(feature.libraries);
+      entries.add(registry.register(feature.name, feature.deps, factory));
     }
-    return Collections.unmodifiableSet(registered);
+    return entries;
+  }
+
+  /**
+   * Parses and registers a single feature xml.
+   * Used for testing.
+   *
+   * @param xml
+   * @return The parsed feature.
+   */
+  public GadgetFeatureRegistry.Entry loadFeature(
+      GadgetFeatureRegistry registry, String xml) throws GadgetException {
+    ParsedFeature feature = parse(xml, "", false);
+
+    JsLibraryFeatureFactory factory
+        = new JsLibraryFeatureFactory(feature.libraries);
+    return registry.register(feature.name, null, factory);
   }
 
   /**
@@ -110,7 +123,7 @@
    * @param features The set of all loaded features
    * @throws GadgetException
    */
-  private void loadFiles(File[] files, Map<String, ParsedFeature> features)
+  private void loadFiles(File[] files, List<ParsedFeature> features)
       throws GadgetException {
     for (File file : files) {
       if (file.isDirectory()) {
@@ -118,7 +131,7 @@
       } else if (file.getName().endsWith(".xml")) {
         ParsedFeature feature = processFile(file);
         if (feature != null) {
-          features.put(feature.name, feature);
+          features.add(feature);
         }
       }
     }
@@ -127,18 +140,19 @@
   /**
    * Loads resources recursively.
    * @param paths The base paths to look for feature.xml
-   * @param feats The set of all loaded features
+   * @param features The set of all loaded features
    * @throws GadgetException
    */
-  private void loadResources(String[] paths, Map<String, ParsedFeature> feats)
+  private void loadResources(String[] paths, List<ParsedFeature> features)
       throws GadgetException {
     try {
       for (String file : paths) {
+        logger.info("Processing resource: " + file);
         String content = ResourceLoader.getContent(file);
         String parent = file.substring(0, file.lastIndexOf('/') + 1);
         ParsedFeature feature = parse(content, parent, true);
         if (feature != null) {
-          feats.put(feature.name, feature);
+          features.add(feature);
         } else {
           logger.warning("Failed to parse feature: " + file);
         }
@@ -177,32 +191,6 @@
   }
 
   /**
-   * Registers a feature and ensures that dependencies are registered in the
-   * proper order.
-   *
-   * @param registry The registry to store the newly registered features to.
-   * @param feature The feature to register.
-   * @param registered Set of all features registered during this operation.
-   * @param all Map of all features that can be loaded during this operation.
-   */
-  private void register(GadgetFeatureRegistry registry,
-                        ParsedFeature feature,
-                        Set<GadgetFeatureRegistry.Entry> registered,
-                        Map<String, ParsedFeature> all) {
-    if (!registered.contains(feature.name)) {
-      for (String dep : feature.deps) {
-        if (all.containsKey(dep) && !registered.contains(dep)) {
-          register(registry, all.get(dep), registered, all);
-        }
-      }
-
-      JsLibraryFeatureFactory factory
-          = new JsLibraryFeatureFactory(feature.gadgetJs, feature.containerJs);
-      registered.add(registry.register(feature.name, feature.deps, factory));
-    }
-  }
-
-  /**
    * Parses the input into a dom tree.
    * @param xml
    * @param path The path the file was loaded from.
@@ -240,12 +228,12 @@
 
     NodeList gadgets = doc.getElementsByTagName("gadget");
     for (int i = 0, j = gadgets.getLength(); i < j; ++i) {
-      processContext(feature, gadgets.item(i), false);
+      processContext(feature, gadgets.item(i), RenderingContext.GADGET);
     }
 
     NodeList containers = doc.getElementsByTagName("container");
     for (int i = 0, j = containers.getLength(); i < j; ++i) {
-      processContext(feature, containers.item(i), true);
+      processContext(feature, containers.item(i), RenderingContext.CONTAINER);
     }
 
     NodeList dependencies = doc.getElementsByTagName("dependency");
@@ -261,24 +249,25 @@
    * to the feature.
    * @param feature
    * @param context
-   * @param isContainer
+   * @param renderingContext
    */
   private void processContext(ParsedFeature feature, Node context,
-                              boolean isContainer) {
+                              RenderingContext renderingContext) {
     NodeList libraries = context.getChildNodes();
+    String syndicator = XmlUtil.getAttribute(context, "synd",
+        SyndicatorConfig.DEFAULT_SYNDICATOR);
     for (int i = 0, j = libraries.getLength(); i < j; ++i) {
       Node node = libraries.item(i);
       String nodeValue = node.getNodeName();
       if ("script".equals(nodeValue)) {
-        NamedNodeMap attrs = node.getAttributes();
-        Node srcNode = attrs.getNamedItem("src");
+        String source = XmlUtil.getAttribute(node, "src");
         String content;
         JsLibrary.Type type;
-        if (srcNode == null) {
+        if (source == null) {
           type = JsLibrary.Type.INLINE;
           content = node.getTextContent();
         } else {
-          content = srcNode.getTextContent();
+          content = source;
           if (content.startsWith("http://")) {
             type = JsLibrary.Type.URL;
           } else if (content.startsWith("//")) {
@@ -298,13 +287,7 @@
           }
         }
         JsLibrary library = JsLibrary.create(type, content);
-        if (library != null) {
-          if (isContainer) {
-            feature.containerJs.add(library);
-          } else {
-            feature.gadgetJs.add(library);
-          }
-        }
+        feature.addLibrary(renderingContext, syndicator, library);
       }
     }
   }
@@ -317,7 +300,27 @@
   public String name = "";
   public String basePath = "";
   public boolean isResource = false;
-  public List<JsLibrary> containerJs = new LinkedList<JsLibrary>();
-  public List<JsLibrary> gadgetJs = new LinkedList<JsLibrary>();
-  public List<String> deps = new LinkedList<String>();
+  final Map<RenderingContext, Map<String, List<JsLibrary>>> libraries;
+  final List<String> deps;
+
+  public ParsedFeature() {
+    libraries = new HashMap<RenderingContext, Map<String, List<JsLibrary>>>();
+    deps = new LinkedList<String>();
+  }
+
+  public void addLibrary(RenderingContext ctx, String synd, JsLibrary library) {
+    Map<String, List<JsLibrary>> ctxLibs = libraries.get(ctx);
+    if (ctxLibs == null) {
+      ctxLibs = new HashMap<String, List<JsLibrary>>();
+      libraries.put(ctx, ctxLibs);
+    }
+
+    List<JsLibrary> syndLibs = ctxLibs.get(synd);
+    if (syndLibs == null) {
+      syndLibs = new LinkedList<JsLibrary>();
+      ctxLibs.put(synd, syndLibs);
+    }
+
+    syndLibs.add(library);
+  }
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibraryFeatureFactory.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibraryFeatureFactory.java?rev=630176&r1=630175&r2=630176&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibraryFeatureFactory.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibraryFeatureFactory.java Fri Feb 22 04:36:32 2008
@@ -17,7 +17,6 @@
  */
 package org.apache.shindig.gadgets;
 
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
@@ -39,13 +38,12 @@
     return feature;
   }
 
-  public JsLibraryFeatureFactory(JsLibrary gadgetLibrary,
-                                 JsLibrary containerLibrary) {
-    this.feature = new JsLibraryFeature(gadgetLibrary, containerLibrary);
-  }
-  public JsLibraryFeatureFactory(List<JsLibrary> gadgetLibraries,
-                                 List<JsLibrary> containerLibraries) {
-    this.feature = new JsLibraryFeature(gadgetLibraries, containerLibraries);
+  /**
+   * @param libraries The libraries to serve when this feature is used.
+   */
+  public JsLibraryFeatureFactory(
+      Map<RenderingContext, Map<String, List<JsLibrary>>> libraries) {
+    this.feature = new JsLibraryFeature(libraries);
   }
   protected JsLibraryFeatureFactory() {
     feature = null;
@@ -53,51 +51,18 @@
 }
 
 class JsLibraryFeature extends GadgetFeature {
-  List<JsLibrary> containerLibraries;
-  List<JsLibrary> gadgetLibraries;
-
-  /**
-   * Creates a JsLibraryFeature with a single library for gadget & container.
-   *
-   * @param gadgetLibrary The library for the gadget, may be null.
-   * @param containerLibrary The library for the container, may be null.
-   */
-  public JsLibraryFeature(JsLibrary gadgetLibrary, JsLibrary containerLibrary) {
-    if (gadgetLibrary == null) {
-      gadgetLibraries = Collections.emptyList();
-    } else {
-      gadgetLibraries
-          = Collections.unmodifiableList(Arrays.asList(gadgetLibrary));
-    }
-
-    if (containerLibrary == null) {
-      containerLibraries = Collections.emptyList();
-    } else {
-      containerLibraries
-          = Collections.unmodifiableList(Arrays.asList(containerLibrary));
-    }
-  }
+  final Map<RenderingContext, Map<String, List<JsLibrary>>> libraries;
 
   /**
    * Creates a JsLibraryFeature with multiple gadget and/or container libraries.
-   * @param gLibraries Libraries to serve for the gadget.
-   * @param cLibraries Libraries to serve for the container.
+   * @param libraries
    */
-  public JsLibraryFeature(List<JsLibrary> gLibraries,
-                          List<JsLibrary> cLibraries) {
-    if (gLibraries == null) {
-      gadgetLibraries = Collections.emptyList();
-    } else {
-      gadgetLibraries
-          = Collections.unmodifiableList(new LinkedList<JsLibrary>(gLibraries));
-    }
-
-    if (cLibraries == null) {
-      containerLibraries = Collections.emptyList();
-    } else {
-      containerLibraries
-        = Collections.unmodifiableList(new LinkedList<JsLibrary>(cLibraries));
-    }
+  public JsLibraryFeature(
+      Map<RenderingContext, Map<String, List<JsLibrary>>> libraries) {
+    // TODO: technically we should copy this, but since currently the callers
+    // always pass us something that won't be modified anyway, we're safe.
+    // Copying this structure is painful.
+    this.libraries = Collections.unmodifiableMap(libraries);
   }
 
   /**
@@ -106,12 +71,32 @@
   @Override
   public List<JsLibrary> getJsLibraries(RenderingContext context,
                                         ProcessingOptions options) {
-    if (context == RenderingContext.GADGET) {
-      return gadgetLibraries;
-    } else if (context == RenderingContext.CONTAINER) {
-      return containerLibraries;
+    List<JsLibrary> libs = null;
+
+    if (context == null || options == null) {
+      // for this special case we return all JS libraries in a single list.
+      libs = new LinkedList<JsLibrary>();
+      for (Map.Entry<RenderingContext, Map<String, List<JsLibrary>>> i :
+          libraries.entrySet()) {
+        for (Map.Entry<String, List<JsLibrary>> e : i.getValue().entrySet()) {
+          libs.addAll(e.getValue());
+        }
+      }
+    } else {
+      Map<String, List<JsLibrary>> contextLibs = libraries.get(context);
+      if (contextLibs != null) {
+        libs = contextLibs.get(options.getSyndicator());
+        if (libs == null) {
+          // Try default.
+          libs = contextLibs.get(SyndicatorConfig.DEFAULT_SYNDICATOR);
+        }
+      }
+    }
+
+    if (libs == null) {
+      return Collections.emptyList();
     }
-    return Collections.emptyList();
+    return libs;
   }
 
   /**
@@ -121,13 +106,8 @@
   public void process(Gadget gadget, GadgetContext context,
       Map<String, String> params) throws GadgetException {
     super.process(gadget, context, params);
-    List<JsLibrary> libraries;
-    if (context.getRenderingContext() == RenderingContext.GADGET) {
-      libraries = gadgetLibraries;
-    } else {
-      libraries = containerLibraries;
-    }
-    for (JsLibrary library : libraries) {
+    for (JsLibrary library : getJsLibraries(context.getRenderingContext(),
+                                            context.getOptions())) {
       gadget.addJsLibrary(library);
     }
   }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SyndicatorConfig.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SyndicatorConfig.java?rev=630176&r1=630175&r2=630176&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SyndicatorConfig.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SyndicatorConfig.java Fri Feb 22 04:36:32 2008
@@ -217,19 +217,20 @@
     try {
       JSONObject contents = new JSONObject(json);
       JSONArray syndicators = contents.getJSONArray(SYNDICATOR_KEY);
-      if (syndicators.length() == 1 &&
-          DEFAULT_SYNDICATOR.equals(syndicators.get(0).toString())) {
-        config.put(DEFAULT_SYNDICATOR, contents);
-        return;
-      } else {
-        JSONObject defaultSynd = config.get(DEFAULT_SYNDICATOR);
-        if (defaultSynd == null) {
+      JSONObject defaultSynd = config.get(DEFAULT_SYNDICATOR);
+      if (defaultSynd == null) {
+        if (DEFAULT_SYNDICATOR.equals(syndicators.get(0))) {
+          defaultSynd = contents;
+          config.put(DEFAULT_SYNDICATOR, contents);
+        } else {
           throw new GadgetException(GadgetException.Code.INVALID_CONFIG,
                                     "No default config registered");
         }
-        for (int i = 0, j = syndicators.length(); i < j; ++i) {
-          // Copy the default object and produce a new one.
-          String syndicator = syndicators.get(i).toString();
+      }
+      for (int i = 0, j = syndicators.length(); i < j; ++i) {
+        // Copy the default object and produce a new one.
+        String syndicator = syndicators.getString(i);
+        if (!DEFAULT_SYNDICATOR.equals(syndicator)) {
           config.put(syndicator, mergeObjects(defaultSynd, contents));
         }
       }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java?rev=630176&r1=630175&r2=630176&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java Fri Feb 22 04:36:32 2008
@@ -33,9 +33,7 @@
 import org.apache.shindig.gadgets.GadgetSpec;
 import org.apache.shindig.gadgets.JsLibrary;
 import org.apache.shindig.gadgets.MessageBundle;
-import org.apache.shindig.gadgets.OpenSocialFeatureFactory;
 import org.apache.shindig.gadgets.ProcessingOptions;
-import org.apache.shindig.gadgets.RenderingContext;
 import org.apache.shindig.gadgets.SyndicatorConfig;
 import org.apache.shindig.gadgets.UserPrefs;
 
@@ -176,10 +174,6 @@
       SyndicatorConfig syndicatorConfig = new SyndicatorConfig(syndicators);
       GadgetFeatureRegistry registry = new GadgetFeatureRegistry(features);
 
-      // We'll add the opensocial-0.7 feature manually for now.
-      // TODO: Something better than this ugly hack.
-      OpenSocialFeatureFactory.register(registry, syndicatorConfig);
-
       GadgetServerConfig config =  new GadgetServerConfig()
           .setExecutor(Executors.newCachedThreadPool())
           .setMessageBundleCache(new BasicGadgetDataCache<MessageBundle>())
@@ -197,10 +191,8 @@
           registry.getAllFeatures().entrySet()) {
         GadgetFeatureFactory factory = entry.getValue().getFeature();
         GadgetFeature feature = factory.create();
-        for (RenderingContext rc : RenderingContext.values()) {
-          for (JsLibrary library : feature.getJsLibraries(rc, null)) {
-            jsBuf.append(library.getContent());
-          }
+        for (JsLibrary library : feature.getJsLibraries(null, null)) {
+          jsBuf.append(library.getContent());
         }
       }
       MessageDigest md;

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsServlet.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsServlet.java?rev=630176&r1=630175&r2=630176&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsServlet.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsServlet.java Fri Feb 22 04:36:32 2008
@@ -96,17 +96,12 @@
 
       StringBuilder jsData = new StringBuilder();
 
-      Set<GadgetFeatureRegistry.Entry> done
-          = new HashSet<GadgetFeatureRegistry.Entry>();
-
       ProcessingOptions opts = new HttpProcessingOptions(req);
       Set<String> features = new HashSet<String>(found.size());
-
-      // TODO: This doesn't work correctly under JDK 1.5, but it does under 1.6
       do {
         for (GadgetFeatureRegistry.Entry entry : found) {
-          if (!done.contains(entry) &&
-              done.containsAll(entry.getDependencies())) {
+          if (!features.contains(entry.getName()) &&
+              features.containsAll(entry.getDependencies())) {
             features.add(entry.getName());
             GadgetFeatureFactory factory = entry.getFeature();
             GadgetFeature feature = factory.create();
@@ -116,10 +111,9 @@
                 jsData.append(lib.getContent());
               }
             }
-            done.add(entry);
           }
         }
-      } while (done.size() != found.size());
+      } while (features.size() != found.size());
 
       if (jsData.length() == 0) {
         resp.setStatus(HttpServletResponse.SC_NOT_FOUND);

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/XmlUtil.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/XmlUtil.java?rev=630176&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/XmlUtil.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/XmlUtil.java Fri Feb 22 04:36:32 2008
@@ -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.util;
+
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+public class XmlUtil {
+
+  /**
+   * Extracts an attribute from a node.
+   *
+   * @param node
+   * @param attr
+   * @param def
+   * @return The value of the attribute, or def
+   */
+  public static String getAttribute(Node node, String attr, String def) {
+    NamedNodeMap attrs = node.getAttributes();
+    Node val = attrs.getNamedItem(attr);
+    if (val != null) {
+      return val.getNodeValue();
+    }
+    return def;
+  }
+
+  /**
+   * @param node
+   * @param attr
+   * @return The value of the given attribute, or null if not present.
+   */
+  public static String getAttribute(Node node, String attr) {
+    return getAttribute(node, attr, null);
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsFeatureLoaderTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsFeatureLoaderTest.java?rev=630176&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsFeatureLoaderTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsFeatureLoaderTest.java Fri Feb 22 04:36:32 2008
@@ -0,0 +1,91 @@
+/*
+ * 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;
+
+import junit.framework.TestCase;
+
+import java.util.List;
+
+public class JsFeatureLoaderTest extends TestCase {
+
+  GadgetFeatureRegistry registry;
+  JsFeatureLoader loader;
+
+  private static final String FEATURE_NAME = "test";
+  private static final String DEF_JS_CONTENT = "var hello = 'world';";
+  private static final String ALT_JS_CONTENT = "function test(){while(true);}";
+  private static final String SYND_A = "test";
+  private static final String SYND_B = "wuwowowaefdf";
+
+
+  @Override
+  public void setUp() throws Exception {
+    registry = new GadgetFeatureRegistry(null);
+    loader = new JsFeatureLoader();
+  }
+
+  public void testBasicLoading() throws Exception {
+    String xml = "<feature>" +
+                 "  <name>" + FEATURE_NAME + "</name>" +
+                 "  <gadget>" +
+                 "    <script>" + DEF_JS_CONTENT + "</script>" +
+                 "  </gadget>" +
+                 "</feature>";
+    GadgetFeatureRegistry.Entry entry = loader.loadFeature(registry, xml);
+
+    assertEquals(FEATURE_NAME, entry.getName());
+    GadgetFeature feature = entry.getFeature().create();
+    List<JsLibrary> libs = feature.getJsLibraries(RenderingContext.GADGET,
+                                                  new ProcessingOptions());
+    assertEquals(1, libs.size());
+    assertEquals(JsLibrary.Type.INLINE, libs.get(0).getType());
+    assertEquals(DEF_JS_CONTENT, libs.get(0).getContent());
+  }
+
+  public void testMultiSyndicators() throws Exception {
+    String xml = "<feature>" +
+                 "  <name>" + FEATURE_NAME + "</name>" +
+                 "  <gadget synd=\"" + SYND_A + "\">" +
+                 "    <script>" + DEF_JS_CONTENT + "</script>" +
+                 "  </gadget>" +
+                 "  <gadget synd=\"" + SYND_B + "\">" +
+                 "    <script>" + ALT_JS_CONTENT + "</script>" +
+                 "  </gadget>" +
+                 "</feature>";
+    GadgetFeatureRegistry.Entry entry = loader.loadFeature(registry, xml);
+    GadgetFeature feature = entry.getFeature().create();
+    List<JsLibrary> libs;
+    libs = feature.getJsLibraries(RenderingContext.GADGET,
+                                  new SyndOptions(SYND_A));
+    assertEquals(DEF_JS_CONTENT, libs.get(0).getContent());
+   libs = feature.getJsLibraries(RenderingContext.GADGET,
+                                 new SyndOptions(SYND_B));
+    assertEquals(ALT_JS_CONTENT, libs.get(0).getContent());
+  }
+}
+
+class SyndOptions extends ProcessingOptions {
+  private final String syndicator;
+  @Override
+  public String getSyndicator() {
+    return syndicator;
+  }
+  public SyndOptions(String syndicator) {
+    this.syndicator = syndicator;
+  }
+}