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/18 23:56:20 UTC

svn commit: r628908 [1/2] - in /incubator/shindig/trunk: config/ features/ features/core.io/ features/core/ features/dynamic-height/ features/rpc/ features/setprefs/ features/settitle/ features/views/ java/gadgets/ java/gadgets/src/main/java/org/apache...

Author: etnu
Date: Mon Feb 18 14:56:14 2008
New Revision: 628908

URL: http://svn.apache.org/viewvc?rev=628908&view=rev
Log:
Changes to satisfy the following JIRA issues:

SHINDIG-22
SHINDIG-44

and partial implementation of SHINDIG-52.

Additionally, this change updates all features to use the standard gadgets.rpc rather than gadgets.ifpc. Since this is no longer compatible with stock IFPC, a future change must provide a shim to map the wire format for gadget to container calls.

Also includes a few minor bug fixes and cleans up files that are no longer used.

Added:
    incubator/shindig/trunk/config/
    incubator/shindig/trunk/config/syndicator.js
    incubator/shindig/trunk/features/core.io/
    incubator/shindig/trunk/features/core.io/feature.xml
    incubator/shindig/trunk/features/core.io/io.js
      - copied, changed from r627880, incubator/shindig/trunk/features/core/io.js
    incubator/shindig/trunk/features/core/config.js
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/OpenSocialFeatureFactory.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/util/ResourceLoader.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/SyndicatorConfigTest.java
Removed:
    incubator/shindig/trunk/features/core/io.js
    incubator/shindig/trunk/java/gadgets/pom.jar.xml
    incubator/shindig/trunk/javascript/gadgets/
Modified:
    incubator/shindig/trunk/features/core/core.js
    incubator/shindig/trunk/features/core/feature.xml
    incubator/shindig/trunk/features/core/legacy.js
    incubator/shindig/trunk/features/dynamic-height/dynamic-height.js
    incubator/shindig/trunk/features/dynamic-height/feature.xml
    incubator/shindig/trunk/features/features.txt
    incubator/shindig/trunk/features/rpc/feature.xml
    incubator/shindig/trunk/features/rpc/rpc.js
    incubator/shindig/trunk/features/setprefs/feature.xml
    incubator/shindig/trunk/features/setprefs/setprefs.js
    incubator/shindig/trunk/features/settitle/feature.xml
    incubator/shindig/trunk/features/settitle/settitle.js
    incubator/shindig/trunk/features/views/feature.xml
    incubator/shindig/trunk/features/views/views.js
    incubator/shindig/trunk/java/gadgets/pom.xml
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BidiSubstituter.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetContext.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetException.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeature.java
    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/GadgetServerConfig.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfigReader.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/JsLibrary.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/MessageBundleSubstituter.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/ModuleSubstituter.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/ProcessingOptions.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/UserPrefSubstituter.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/GadgetRenderingServlet.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpProcessingOptions.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsServlet.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcGadgetJob.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/JsonRpcRequest.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/RpcException.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/InputStreamConsumer.java
    incubator/shindig/trunk/java/gadgets/src/main/webapp/WEB-INF/web.xml
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetSpecTestFixture.java
    incubator/shindig/trunk/javascript/container/gadgets.js
    incubator/shindig/trunk/javascript/container/sample-rpc.html
    incubator/shindig/trunk/javascript/container/sample1.html
    incubator/shindig/trunk/javascript/container/sample2.html
    incubator/shindig/trunk/javascript/container/sample3.html
    incubator/shindig/trunk/javascript/container/sample4.html
    incubator/shindig/trunk/javascript/container/sample5.html
    incubator/shindig/trunk/javascript/container/sample6.html
    incubator/shindig/trunk/javascript/container/sample7.html

Added: incubator/shindig/trunk/config/syndicator.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/config/syndicator.js?rev=628908&view=auto
==============================================================================
--- incubator/shindig/trunk/config/syndicator.js (added)
+++ incubator/shindig/trunk/config/syndicator.js Mon Feb 18 14:56:14 2008
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+// Default syndicator configuration. Rather than replacing this
+// file, you should create your own syndicator.js file and
+// load it directly by modifying the value of web.xml.
+// All configurations will automatically inherit values from this
+// config, so you only need to provide configuration for items
+// that you require explicit special casing for.
+
+// Please namespace your attributes using the same conventions
+// as you would for javascript objects, e.g. gadgets.features
+// rather than "features".
+
+// NOTE: Please leave trailing commas to reduce errors when adding new fields.
+// All known common server-side JSON parsers will handle this without issue.
+
+// Syndicator must be an array; this allows multiple syndicators
+// 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.
+
+// This config data will be passed down to javascript. Please
+// configure your object using the feature name rather than
+// the javascript name.
+
+// Only configuration for required features will be used.
+// See individual feature.xml files for configuration details.
+"gadgets.features" : {
+  "core.io" : {
+    "proxyUrl" : "http://www.gmodules.com/ig/proxy?url=%url%",
+    "jsonProxyUrl" : "proxy?output=js",
+  },
+  "views" : {
+    "default" : {
+      "isOnlyVisible" : false,
+      "aliases": ["DASHBOARD"],
+    },
+    "profile" : {
+      "isOnlyVisible" : false,
+    },
+    "canvas" : {
+      "isOnlyVisible" : true,
+      "aliases" : ["FULL_PAGE"]
+    },
+  },
+  "rpc" : {
+    // This should never be on the same host in a production environment!
+    // Only use this for TESTING!
+    "parentRelayUrl" : "files/container/rpc_relay.html"
+  },
+}}

Added: incubator/shindig/trunk/features/core.io/feature.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core.io/feature.xml?rev=628908&view=auto
==============================================================================
--- incubator/shindig/trunk/features/core.io/feature.xml (added)
+++ incubator/shindig/trunk/features/core.io/feature.xml Mon Feb 18 14:56:14 2008
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<!--
+  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.
+-->
+<feature>
+<!--
+  Required configuration:
+
+  proxyUrl: A url template containing the placeholder "%url%", which will be
+      used for all calls to gadgets.io.getProxyUrl(string), with the value
+      passed in being used as the replacement.
+  jsonProxyUrl: A url pointing to the JSON proxy endpoint, used by
+      gadgets.io.makeRequest. All data passed to this end point will be
+      encoded inside of the POST body.
+-->
+  <name>core.io</name>
+  <dependency>core</dependency>
+  <gadget>
+    <script src="io.js"/>
+  </gadget>
+</feature>

Copied: incubator/shindig/trunk/features/core.io/io.js (from r627880, incubator/shindig/trunk/features/core/io.js)
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core.io/io.js?p2=incubator/shindig/trunk/features/core.io/io.js&p1=incubator/shindig/trunk/features/core/io.js&r1=627880&r2=628908&rev=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/features/core/io.js (original)
+++ incubator/shindig/trunk/features/core.io/io.js Mon Feb 18 14:56:14 2008
@@ -120,6 +120,20 @@
     callback(resp);
   }
 
+  /**
+   * @param {Object} configuration Configuration settings
+   * @private
+   */
+  function init (configuration) {
+    config = configuration["core.io"];
+  }
+
+  var requiredConfig = {
+    proxyUrl: new gadgets.config.RegExValidator(/.*%url%.*/),
+    jsonProxyUrl: gadgets.config.NonEmptyStringValidator
+  };
+  gadgets.config.register("core.io", requiredConfig, init);
+
   return /** @scope gadgets.io */ {
     /**
      * Fetches content from the provided URL and feeds that content into the
@@ -213,24 +227,6 @@
      */
     getProxyUrl : function (url) {
       return config.proxyUrl.replace("%url%", encodeURIComponent(url));
-    },
-
-    /**
-     * Initializes fetchers
-     *
-     * @param {Object} configuration Configuration settings
-     *     Required:
-     *       - proxyUrl: The url for content proxy requests. Include %url%
-     *           as a placeholder for the actual url.
-     *       - jsonProxyUrl: The url for dynamic proxy requests. Include %url%
-     *           as a placeholder for the actual url.
-     * @private
-     */
-    init : function (configuration) {
-      config = configuration;
-      if (!config.proxyUrl || !config.jsonProxyUrl) {
-        throw new Error("proxyUrl and jsonProxyUrl are required.");
-      }
     }
   };
 }();

Added: incubator/shindig/trunk/features/core/config.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core/config.js?rev=628908&view=auto
==============================================================================
--- incubator/shindig/trunk/features/core/config.js (added)
+++ incubator/shindig/trunk/features/core/config.js Mon Feb 18 14:56:14 2008
@@ -0,0 +1,225 @@
+/*
+ * 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.
+ */
+
+/**
+ * @fileoverview
+ *
+ * Provides unified configuration for all features.
+ *
+ * This is a custom shindig library that has not yet been submitted for
+ * standardization. It is designed to make developing of features for the
+ * opensocial / gadgets platforms easier and is intended as a supplemental
+ * tool to Shindig's standardized feature loading mechanism.
+ *
+ * Usage:
+ * First, you must register a component that needs configuration:
+ * <pre>
+ *   var config = {
+ *     name : gadgets.config.NonEmptyStringValidator,
+ *     url : new gadgets.config.RegExValidator(/.+%mySpecialValue%.+/)
+ *   };
+ *   gadgets.config.register("my-feature", config, myCallback);
+ * </pre>
+ *
+ * This will register a component named "my-feature" that expects input config
+ * containing a "name" field with a value that is a non-empty string, and a
+ * "url" field with a value that matches the given regular expression.
+ *
+ * When gadgets.config.init is invoked by the container, it will automatically
+ * validate your registered configuration and will throw an exception if
+ * the provided configuration does not match what was required.
+ *
+ * Your callback will be invoked by passing all configuration data passed to
+ * gadgets.config.init, which allows you to optionally inspect configuration
+ * from other features, if present.
+ *
+ * Note that the container may optionally bypass configuration validation for
+ * performance reasons. This does not mean that you should duplicate validation
+ * code, it simply means that validation will likely only be performed in debug
+ * builds, and you should assume that production builds always have valid
+ * configuration.
+ */
+
+var gadgets = gadgets || {};
+
+gadgets.config = function() {
+  var components = {};
+
+  return {
+    /**
+     * Registers a configurable component and its configuration parameters.
+     *
+     * @param {String} component The name of the component to register. Should
+     *     be the same as the fully qualified name of the <Require> feature or
+     *     the fully qualified javascript object reference (e.g. gadgets.io).
+     * @param {Object} opt_validators Mapping of option name to validation
+     *     functions that take the form function(data) {return isValid(data);}
+     * @param {Function} opt_callback A function to be invoked when a
+     *     configuration is registered. If passed, this function will be invoked
+     *     immediately after a call to init has been made. Do not assume that
+     *     dependent libraries have been configured until after init is
+     *     complete. If you rely on this, it is better to defer calling
+     *     dependent libraries until you can be sure that configuration is
+     *     complete. Takes the form function(config), where config will be
+     *     all registered config data for all components. This allows your
+     *     component to read configuration from other components.
+     * @throws {Error} If the component has already been registered.
+     */
+    register: function(component, opt_validators, opt_callback) {
+      if (components[component]) {
+        throw new Error('Component "' + component + '" is already registered.');
+      }
+      components[component] = {
+        validators: opt_validators || {},
+        callback: opt_callback
+      };
+    },
+
+    /**
+     * Retrieves configuration data on demand.
+     *
+     * @param {String} opt_component The component to fetch. If not provided
+     *     all configuration will be returned.
+     * @return {Object} The requested configuration.
+     * @throws {Error} If the given component has not been registered
+     */
+    get: function(opt_component) {
+      if (opt_component) {
+        if (!components[opt_component]) {
+          throw new Error('Component "' + opt_component + '" not registered.');
+        }
+        return configuration[opt_component] || {};
+      }
+      return configuration;
+    },
+
+    /**
+     * Initializes the configuration.
+     *
+     * @param {Object} config The full set of configuration data.
+     * @param {Boolean} opt_noValidation True if you want to skip validation.
+     * @throws {Error} If there is a configuration error.
+     */
+    init: function(config, opt_noValidation) {
+      configuration = config;
+      for (var name in components) {
+        var component = components[name],
+            conf = config[name],
+            validators = component.validators;
+        if (!opt_noValidation) {
+          for (var validator in validators) {
+            if (!validators[validator](conf[validator])) {
+              throw new Error('Invalid config value "' + conf[validator] +
+                  '" for parameter "' + validator + '" in component "' +
+                  name + '"');
+            }
+          }
+        }
+        if (component.callback) {
+          component.callback(config);
+        }
+      }
+    },
+
+    // Standard validators go here.
+
+    /**
+     * Ensures that data is one of a fixed set of items.
+     * @param {Array.<String>} list The list of valid values.
+     * Also supports argument sytax: EnumValidator("Dog", "Cat", "Fish");
+     */
+    EnumValidator: function(list) {
+      var listItems = [];
+      if (arguments.length > 1) {
+        for (var i = 0, arg; arg = arguments[i]; ++i) {
+          listItems.push(arg);
+        }
+      } else {
+        listItems = list;
+      }
+      return function(data) {
+        for (var i = 0, test; test = listItems[i]; ++i) {
+          if (data === listItems[i]) {
+            return true;
+          }
+        }
+      }
+      return false;
+    },
+
+    /**
+     * Tests the value against a regular expression.
+     */
+    RegExValidator: function(re) {
+      return function(data) {
+        return re.test(data);
+      }
+    },
+
+    /**
+     * Validates that a value was provided.
+     */
+    ExistsValidator: function(data) {
+      return typeof data !== "undefined";
+    },
+
+    /**
+     * Validates that a value is a non-empty string.
+     */
+    NonEmptyStringValidator: function(data) {
+      return typeof data === "string" && data.length > 0
+    },
+
+    /**
+     * Validates that the value is a boolean.
+     */
+    BooleanValidator: function(data) {
+      return !!data;
+    },
+
+    /**
+     * Similar to the ECMAScript4 virtual typing system, ensures that
+     * whatever object was passed in is "like" the existing object.
+     * Doesn't actually do type validation though, but instead relies
+     * on other validators.
+     *
+     * example:
+     *
+     *  var validator = new gadgets.config.LikeValidator(
+     *    "booleanField" : gadgets.config.BooleanValidator,
+     *    "regexField" : new gadgets.config.RegExValidator(/foo.+/);
+     *  );
+     *
+     * This can be used recursively as well to validate sub-objects.
+     *
+     * @param {Object} test The object to test against.
+     */
+    LikeValidator : function(test) {
+      return function(data) {
+        for (var member in test) {
+          var t = test[member];
+          if (!t(data[member])) {
+            return false;
+          }
+        }
+        return true;
+      };
+    }
+  };
+}();
\ No newline at end of file

Modified: incubator/shindig/trunk/features/core/core.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core/core.js?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/features/core/core.js (original)
+++ incubator/shindig/trunk/features/core/core.js Mon Feb 18 14:56:14 2008
@@ -17,4 +17,4 @@
  * under the License.
  */
 
-var gadgets = gadgets || {};
+var gadgets = {};

Modified: incubator/shindig/trunk/features/core/feature.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core/feature.xml?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/features/core/feature.xml (original)
+++ incubator/shindig/trunk/features/core/feature.xml Mon Feb 18 14:56:14 2008
@@ -20,16 +20,10 @@
   <name>core</name>
   <gadget>
     <script src="core.js"/>
+    <script src="config.js"/>
     <script src="util.js"/>
     <script src="prefs.js"/>
     <script src="json.js"/>
-    <script src="io.js"/>
-    <script><![CDATA[
-      gadgets.io.init({
-        proxyUrl: "http://www.gmodules.com/ig/proxy?url=%url%",
-        jsonProxyUrl: "proxy?output=js"
-      });
-    ]]></script>
     <script src="legacy.js"/>
   </gadget>
   <container>

Modified: incubator/shindig/trunk/features/core/legacy.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core/legacy.js?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/features/core/legacy.js (original)
+++ incubator/shindig/trunk/features/core/legacy.js Mon Feb 18 14:56:14 2008
@@ -87,11 +87,11 @@
  * @return {Array.<HTMLElement>} All elements of this tag type.
  */
 function _gelstn(tag) {
-  if (n === "*" && document.all) {
+  if (tag === "*" && document.all) {
     return document.all;
   }
   return document.getElementsByTagName ?
-         document.getElementsByTagName(n) : [];
+         document.getElementsByTagName(tag) : [];
 }
 
 /**

Modified: incubator/shindig/trunk/features/dynamic-height/dynamic-height.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/dynamic-height/dynamic-height.js?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/features/dynamic-height/dynamic-height.js (original)
+++ incubator/shindig/trunk/features/dynamic-height/dynamic-height.js Mon Feb 18 14:56:14 2008
@@ -31,107 +31,111 @@
  */
 gadgets.window = gadgets.window || {};
 
-/**
- * Detects the inner dimensions of a frame.
- * See: http://www.quirksmode.org/viewport/compatibility.html for more
- * information.
- * @returns {Object} An object with width and height properties.
- * @member gadgets.window
- */
-gadgets.window.getViewportDimensions = function() {
-  var x,y;
-  if (self.innerHeight) {
-    // all except Explorer
-    x = self.innerWidth;
-    y = self.innerHeight;
-  } else if (document.documentElement &&
-             document.documentElement.clientHeight) {
-    // Explorer 6 Strict Mode
-    x = document.documentElement.clientWidth;
-    y = document.documentElement.clientHeight;
-  } else if (document.body) {
-    // other Explorers
-    x = document.body.clientWidth;
-    y = document.body.clientHeight;
-  } else {
-    x = 0;
-    y = 0;
-  }
-  return {width: x, height: y};
-};
-
-/**
- * Adjusts the gadget height
- * @param {Number} opt_height An optional preferred height in pixels. If not
- *     specified, will attempt to fit the gadget to its content.
- * @member gadgets.window
- */
-gadgets.window.adjustHeight = function(opt_height) {
-  var newHeight = parseInt(opt_height, 10);
-  if (isNaN(newHeight)) {
-    // Resize the gadget to fit its content.
-
-    // Calculating inner content height is hard and different between
-    // browsers rendering in Strict vs. Quirks mode.  We use a combination of
-    // three properties within document.body and document.documentElement:
-    // - scrollHeight
-    // - offsetHeight
-    // - clientHeight
-    // These values differ significantly between browsers and rendering modes.
-    // But there are patterns.  It just takes a lot of time and persistence
-    // to figure out.
-
-    // Get the height of the viewport
-    var vh = gadgets.window.getViewportDimensions().height;
-    var body = document.body;
-    var docEl = document.documentElement;
-    if (document.compatMode == 'CSS1Compat' && docEl.scrollHeight) {
-      // In Strict mode:
-      // The inner content height is contained in either:
-      //    document.documentElement.scrollHeight
-      //    document.documentElement.offsetHeight
-      // Based on studying the values output by different browsers,
-      // use the value that's NOT equal to the viewport height found above.
-      newHeight = docEl.scrollHeight != vh ?
-                   docEl.scrollHeight : docEl.offsetHeight;
+// we wrap these in an anonymous function to avoid storing private data
+// as members of gadgets.window.
+(function() {
+
+  var oldHeight;
+
+  /**
+   * Detects the inner dimensions of a frame.
+   * See: http://www.quirksmode.org/viewport/compatibility.html for more
+   * information.
+   * @returns {Object} An object with width and height properties.
+   * @member gadgets.window
+   */
+  gadgets.window.getViewportDimensions = function() {
+    var x,y;
+    if (self.innerHeight) {
+      // all except Explorer
+      x = self.innerWidth;
+      y = self.innerHeight;
+    } else if (document.documentElement &&
+               document.documentElement.clientHeight) {
+      // Explorer 6 Strict Mode
+      x = document.documentElement.clientWidth;
+      y = document.documentElement.clientHeight;
+    } else if (document.body) {
+      // other Explorers
+      x = document.body.clientWidth;
+      y = document.body.clientHeight;
     } else {
-      // In Quirks mode:
-      // documentElement.clientHeight is equal to documentElement.offsetHeight
-      // except in IE.  In most browsers, document.documentElement can be used
-      // to calculate the inner content height.
-      // However, in other browsers (e.g. IE), document.body must be used
-      // instead.  How do we know which one to use?
-      // If document.documentElement.clientHeight does NOT equal
-      // document.documentElement.offsetHeight, then use document.body.
-      var sh = docEl.scrollHeight;
-      var oh = docEl.offsetHeight;
-      if (docEl.clientHeight != oh) {
-        sh = body.scrollHeight;
-        oh = body.offsetHeight;
-      }
+      x = 0;
+      y = 0;
+    }
+    return {width: x, height: y};
+  };
 
-      // Detect whether the inner content height is bigger or smaller
-      // than the bounding box (viewport).  If bigger, take the larger
-      // value.  If smaller, take the smaller value.
-      if (sh > vh) {
-        // Content is larger
-        newHeight = sh > oh ? sh : oh;
+  /**
+   * Adjusts the gadget height
+   * @param {Number} opt_height An optional preferred height in pixels. If not
+   *     specified, will attempt to fit the gadget to its content.
+   * @member gadgets.window
+   */
+  gadgets.window.adjustHeight = function(opt_height) {
+    var newHeight = parseInt(opt_height, 10);
+    if (isNaN(newHeight)) {
+      // Resize the gadget to fit its content.
+
+      // Calculating inner content height is hard and different between
+      // browsers rendering in Strict vs. Quirks mode.  We use a combination of
+      // three properties within document.body and document.documentElement:
+      // - scrollHeight
+      // - offsetHeight
+      // - clientHeight
+      // These values differ significantly between browsers and rendering modes.
+      // But there are patterns.  It just takes a lot of time and persistence
+      // to figure out.
+
+      // Get the height of the viewport
+      var vh = gadgets.window.getViewportDimensions().height;
+      var body = document.body;
+      var docEl = document.documentElement;
+      if (document.compatMode == 'CSS1Compat' && docEl.scrollHeight) {
+        // In Strict mode:
+        // The inner content height is contained in either:
+        //    document.documentElement.scrollHeight
+        //    document.documentElement.offsetHeight
+        // Based on studying the values output by different browsers,
+        // use the value that's NOT equal to the viewport height found above.
+        newHeight = docEl.scrollHeight != vh ?
+                     docEl.scrollHeight : docEl.offsetHeight;
       } else {
-        // Content is smaller
-        newHeight = sh < oh ? sh : oh;
+        // In Quirks mode:
+        // documentElement.clientHeight is equal to documentElement.offsetHeight
+        // except in IE.  In most browsers, document.documentElement can be used
+        // to calculate the inner content height.
+        // However, in other browsers (e.g. IE), document.body must be used
+        // instead.  How do we know which one to use?
+        // If document.documentElement.clientHeight does NOT equal
+        // document.documentElement.offsetHeight, then use document.body.
+        var sh = docEl.scrollHeight;
+        var oh = docEl.offsetHeight;
+        if (docEl.clientHeight != oh) {
+          sh = body.scrollHeight;
+          oh = body.offsetHeight;
+        }
+
+        // Detect whether the inner content height is bigger or smaller
+        // than the bounding box (viewport).  If bigger, take the larger
+        // value.  If smaller, take the smaller value.
+        if (sh > vh) {
+          // Content is larger
+          newHeight = sh > oh ? sh : oh;
+        } else {
+          // Content is smaller
+          newHeight = sh < oh ? sh : oh;
+        }
       }
     }
-  }
 
-  // Only make the IFPC call if height has changed
-  if (newHeight != gadgets.window.oldHeight_) {
-    gadgets.window.oldHeight_ = newHeight;
-    var modId = 'remote_iframe_' + (new gadgets.Prefs()).getModuleId();
-    var ifpcRelay = gadgets.util.getUrlParameters().parent || '';
-    gadgets.ifpc_.call(modId, "resize_iframe", [modId, newHeight],
-      ifpcRelay, null, '');
-  }
-};
+    // Only make the IFPC call if height has changed
+    if (newHeight != oldHeight) {
+      oldHeight = newHeight;
+      gadgets.rpc.call(null, "resize_iframe", null, newHeight);
+    }
+  };
+}());
 
 // Alias for legacy code
 var _IG_AdjustIFrameHeight = gadgets.window.adjustHeight;

Modified: incubator/shindig/trunk/features/dynamic-height/feature.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/dynamic-height/feature.xml?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/features/dynamic-height/feature.xml (original)
+++ incubator/shindig/trunk/features/dynamic-height/feature.xml Mon Feb 18 14:56:14 2008
@@ -18,7 +18,7 @@
 -->
 <feature>
   <name>dynamic-height</name>
-  <dependency>ifpc</dependency>
+  <dependency>rpc</dependency>
   <gadget>
     <script src="dynamic-height.js"/>
   </gadget>

Modified: incubator/shindig/trunk/features/features.txt
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/features.txt?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/features/features.txt (original)
+++ incubator/shindig/trunk/features/features.txt Mon Feb 18 14:56:14 2008
@@ -1,15 +1,16 @@
 features/analytics/feature.xml
 features/caja/feature.xml
+features/core.io/feature.xml
 features/core/feature.xml
 features/dynamic-height/feature.xml
 features/flash/feature.xml
 features/ifpc/feature.xml
-features/rpc/feature.xml
+features/minimessage/feature.xml
 features/opensocial-reference/feature.xml
 features/opensocial-samplecontainer/feature.xml
+features/rpc/feature.xml
 features/setprefs/feature.xml
 features/settitle/feature.xml
-features/minimessage/feature.xml
-features/tabs/feature.xml
 features/skins/feature.xml
+features/tabs/feature.xml
 features/views/feature.xml

Modified: incubator/shindig/trunk/features/rpc/feature.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/rpc/feature.xml?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/features/rpc/feature.xml (original)
+++ incubator/shindig/trunk/features/rpc/feature.xml Mon Feb 18 14:56:14 2008
@@ -17,8 +17,16 @@
 specific language governing permissions and limitations under the License.
 -->
 <feature>
+<!--
+Required config:
+
+parentRelayUrl: The url of the relay file for this service.
+-->
   <name>rpc</name>
   <gadget>
     <script src="rpc.js"/>
   </gadget>
+  <container>
+    <script src="rpc.js"/>
+  </container>
 </feature>

Modified: incubator/shindig/trunk/features/rpc/rpc.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/rpc/rpc.js?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/features/rpc/rpc.js (original)
+++ incubator/shindig/trunk/features/rpc/rpc.js Mon Feb 18 14:56:14 2008
@@ -29,37 +29,33 @@
  * @name gadgets.rpc
  */
 gadgets.rpc = function() {
-  var services_ = {};
-  var iframePool_ = [];
-  var relayUrl_ = {};
-  var callId_ = 0;
-  var callbacks_ = {};
+  var services = {};
+  var iframePool = [];
+  var relayUrl = {};
+  var callId = 0;
+  var callbacks = {};
 
   // Pick the most efficient RPC relay mechanism
-  var relayChannel_ = typeof document.postMessage === 'function' ? 'dpm' :
-                      typeof window.postMessage === 'function' ? 'wpm' :
-                      'ifpc';
-  if (relayChannel_ === 'dpm' || relayChannel_ === 'wpm') {
+  var relayChannel = typeof document.postMessage === 'function' ? 'dpm' :
+                     typeof window.postMessage === 'function' ? 'wpm' :
+                     'ifpc';
+  if (relayChannel === 'dpm' || relayChannel === 'wpm') {
     document.addEventListener('message', function(packet) {
       // TODO validate packet.domain for security reasons
       process(gadgets.json.parse(packet.data));
     }, false);
   }
 
-  // Parent relay URL retrieval
-  var args = gadgets.util.getUrlParameters();
-  relayUrl_['..'] = args.rpc_relay || args.parent;
-
   // Default RPC handler
-  services_[''] = function() {
+  services[''] = function() {
     throw new Error('Unknown RPC service: ' + this.s);
   };
 
   // Special RPC handler for callbacks
-  services_['__cb'] = function(callbackId, result) {
-    var callback = callbacks_[callbackId];
+  services['__cb'] = function(callbackId, result) {
+    var callback = callbacks[callbackId];
     if (callback) {
-      delete callbacks_[callbackId];
+      delete callbacks[callbackId];
       callback(result);
     }
   };
@@ -72,7 +68,7 @@
   function process(rpc) {
     if (rpc && typeof rpc.s === 'string' && typeof rpc.f === 'string' &&
         rpc.a instanceof Array) {
-      var result = (services_[rpc.s] || services_['']).apply(rpc, rpc.a);
+      var result = (services[rpc.s] || services['']).apply(rpc, rpc.a);
       if (rpc.c) {
         gadgets.rpc.call(rpc.f, '__cb', null, rpc.c, result);
       }
@@ -87,8 +83,8 @@
   function emitInvisibleIframe(src) {
     var iframe;
     // Recycle IFrames
-    for (var i = iframePool_.length - 1; i >=0; --i) {
-      var ifr = iframePool_[i];
+    for (var i = iframePool.length - 1; i >=0; --i) {
+      var ifr = iframePool[i];
       if (ifr && (ifr.recyclable || ifr.readyState === 'complete')) {
         ifr.parentNode.removeChild(ifr);
         if (window.ActiveXObject) {
@@ -96,8 +92,8 @@
           // cannot reuse the IFRAME because a navigational click sound will
           // be triggered when we set the SRC attribute.
           // Other browsers scan the pool for a free iframe to reuse.
-          iframePool_[i] = ifr = null;
-          iframePool_.splice(i, 1);
+          iframePool[i] = ifr = null;
+          iframePool.splice(i, 1);
         } else {
           ifr.recyclable = false;
           iframe = ifr;
@@ -112,12 +108,27 @@
       iframe.style.visibility = 'hidden';
       iframe.style.position = 'absolute';
       iframe.onload = function() { this.recyclable = true; };
-      iframePool_.push(iframe);
+      iframePool.push(iframe);
     }
     iframe.src = src;
     setTimeout(function() { document.body.appendChild(iframe); }, 0);
   }
 
+  // gadgets.config might not be available, such as when serving container js.
+  if (gadgets.config) {
+    /**
+     * Initializes RPC from the provided configuration.
+     */
+    function init(config) {
+      relayUrl['..'] = config.rpc.parentRelayUrl;
+    }
+
+    var requiredConfig = {
+      parentRelayUrl : gadgets.config.NonEmptyStringValidator
+    };
+    gadgets.config.register("rpc", requiredConfig, init);
+  }
+
   return /** @scope gadgets.rpc */ {
     /**
      * Registers an RPC service.
@@ -127,7 +138,7 @@
      * @member gadgets.rpc
      */
     register: function(serviceName, handler) {
-      services_[serviceName] = handler;
+      services[serviceName] = handler;
     },
 
     /**
@@ -137,7 +148,7 @@
      * @member gadgets.rpc
      */
     unregister: function(serviceName) {
-      delete services_[serviceName];
+      delete services[serviceName];
     },
 
     /**
@@ -148,7 +159,7 @@
      * @member gadgets.rpc
      */
     registerDefault: function(handler) {
-      services_[''] = handler;
+      services[''] = handler;
     },
 
     /**
@@ -158,12 +169,12 @@
      * @member gadgets.rpc
      */
     unregisterDefault: function() {
-      delete services_[''];
+      delete services[''];
     },
 
     /**
      * Calls an RPC service.
-     * @param {String} targetId Id of the RPC service provider.
+     * @param {String} targetId Module Id of the RPC service provider.
      *                          Empty if calling the parent container.
      * @param {String} serviceName Service name to call.
      * @param {Function|null} callback Callback function (if any) to process
@@ -173,20 +184,27 @@
      * @member gadgets.rpc
      */
     call: function(targetId, serviceName, callback, var_args) {
-      ++callId_;
+      ++callId;
       targetId = targetId || '..';
       if (callback) {
-        callbacks_[callId_] = callback;
+        callbacks[callId] = callback;
+      }
+      var from;
+      if (targetId === '..') {
+        from = window.name;
+      } else {
+        from = '..';
+        targetId = idFormat.replace(/%targetId%/g, targetId);
       }
-      var from = targetId === '..' ? window.name : '..';
+
       var rpcData = gadgets.json.stringify({
         s: serviceName,
         f: from,
-        c: callback ? callId_ : 0,
+        c: callback ? callId : 0,
         a: Array.prototype.slice.call(arguments, 3)
       });
 
-      switch (relayChannel_) {
+      switch (relayChannel) {
       case 'dpm': // use document.postMessage
         var targetDoc = targetId === '..' ? parent.document :
                                             frames[targetId].document;
@@ -197,15 +215,13 @@
         targetWin.postMessage(rpcData);
         break;
       default: // use 'ifpc' as a fallback mechanism
-        var relayUrl = gadgets.rpc.getRelayUrl(targetId);
-        if (/^http[s]?:\/\//.test(relayUrl)) {
-          // IFrame packet format:
-          // # targetId & sourceId@callId & packetNum & packetId & packetData
-          // TODO split message if too long
-          var src = [relayUrl, '#', targetId, '&', from, '@', callId_,
-                     '&1&0&', encodeURIComponent(rpcData)].join('');
-          emitInvisibleIframe(src);
-        }
+        var relay = gadgets.rpc.getRelayUrl(targetId);
+        // IFrame packet format:
+        // # targetId & sourceId@callId & packetNum & packetId & packetData
+        // TODO split message if too long
+        var src = [relay, '#', targetId, '&', from, '@', callId,
+                   '&1&0&', rpcData].join('');
+        emitInvisibleIframe(src);
       }
     },
 
@@ -217,7 +233,7 @@
      * @member gadgets.rpc
      */
     getRelayUrl: function(targetId) {
-      return relayUrl_[targetId];
+      return relayUrl[targetId];
     },
 
     /**
@@ -228,7 +244,7 @@
      * @member gadgets.rpc
      */
     setRelayUrl: function(targetId, relayUrl) {
-      relayUrl_[targetId] = relayUrl;
+      relayUrl[targetId] = relayUrl;
     },
 
     /**
@@ -242,7 +258,7 @@
      * @member gadgets.rpc
      */
     getRelayChannel: function() {
-      return relayChannel_;
+      return relayChannel;
     },
 
     /**
@@ -258,7 +274,7 @@
       if (fragment.length > 4) {
         // TODO parse fragment[1..3] to merge multi-fragment messages
         process(gadgets.json.parse(
-                decodeURIComponent(fragment[fragment.length - 1])));
+            decodeURIComponent(fragment[fragment.length - 1])));
       }
     }
   };

Modified: incubator/shindig/trunk/features/setprefs/feature.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/setprefs/feature.xml?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/features/setprefs/feature.xml (original)
+++ incubator/shindig/trunk/features/setprefs/feature.xml Mon Feb 18 14:56:14 2008
@@ -18,7 +18,7 @@
 -->
 <feature>
   <name>setprefs</name>
-  <dependency>ifpc</dependency>
+  <dependency>rpc</dependency>
   <gadget>
     <script src="setprefs.js"/>
   </gadget>

Modified: incubator/shindig/trunk/features/setprefs/setprefs.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/setprefs/setprefs.js?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/features/setprefs/setprefs.js (original)
+++ incubator/shindig/trunk/features/setprefs/setprefs.js Mon Feb 18 14:56:14 2008
@@ -42,13 +42,14 @@
     gadgets.prefs_.setPref(this.moduleId_, key, value);
   }
 
-  var modId = 'remote_iframe_' + this.getModuleId();
-  var params = gadgets.util.getUrlParameters();
-  var ifpcRelay = (params.parent || '') + '/ig/ifpc_relay';
-  var ifpcArgs = Array.prototype.slice.call(arguments);
-  ifpcArgs.unshift(''); // security token placeholder
-  ifpcArgs.unshift(modId);
-  gadgets.ifpc_.call(modId, 'set_pref', ifpcArgs, ifpcRelay, null, '');
+  var args = [
+    null, // go to parent
+    "set_pref", // service name
+    null // no callback
+  ];
+  // and add the other params...
+  args.concat(Array.prototype.slice.call(arguments));
+  gadgets.rpc.call.apply(gadgets.rpc, args);
 };
 
 /**

Modified: incubator/shindig/trunk/features/settitle/feature.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/settitle/feature.xml?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/features/settitle/feature.xml (original)
+++ incubator/shindig/trunk/features/settitle/feature.xml Mon Feb 18 14:56:14 2008
@@ -18,7 +18,7 @@
 -->
 <feature>
   <name>settitle</name>
-  <dependency>ifpc</dependency>
+  <dependency>rpc</dependency>
   <gadget>
     <script src="settitle.js"/>
   </gadget>

Modified: incubator/shindig/trunk/features/settitle/settitle.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/settitle/settitle.js?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/features/settitle/settitle.js (original)
+++ incubator/shindig/trunk/features/settitle/settitle.js Mon Feb 18 14:56:14 2008
@@ -32,9 +32,7 @@
  * @scope gadgets.window
  */
 gadgets.window.setTitle = function(title) {
-  var modId = 'remote_iframe_' + (new gadgets.Prefs()).getModuleId();
-  var ifpcRelay = gadgets.util.getUrlParameters().parent || '';
-  gadgets.ifpc_.call(modId, 'set_title', [modId, title], ifpcRelay, null, '');
+  gadgets.rpc.call(null, "set_title", null, title);
 };
 
 // Alias for legacy code

Modified: incubator/shindig/trunk/features/views/feature.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/views/feature.xml?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/features/views/feature.xml (original)
+++ incubator/shindig/trunk/features/views/feature.xml Mon Feb 18 14:56:14 2008
@@ -17,21 +17,16 @@
 specific language governing permissions and limitations under the License.
 -->
 <feature>
+<!--
+Required configuration:
+A map of view names to view attributes. Examples:
+
+
+-->
+
   <name>views</name>
-  <!-- TODO: Use rpc when it becomes available -->
-  <dependency>ifpc</dependency>
+  <dependency>rpc</dependency>
   <gadget>
     <script src="views.js"/>
-    <!-- TODO: Clean this up and unify the configuration model -->
-    <script><![CDATA[
-      gadgets.views.init({
-        // Some standard views. Feel free to change these to use whatever
-        // views your container supports.
-        "default" : false,
-        "profile" : false,
-        "canvas" : true
-      });
-    ]]>
-    </script>
   </gadget>
 </feature>

Modified: incubator/shindig/trunk/features/views/views.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/views/views.js?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/features/views/views.js (original)
+++ incubator/shindig/trunk/features/views/views.js Mon Feb 18 14:56:14 2008
@@ -44,20 +44,49 @@
    */
   var params = {};
 
+  /**
+   * Initializes views. Assumes that the current view is the "view"
+   * url parameter (or default if "view" isn't supported), and that
+   * all view parameters are in the form view-<name>
+   * TODO: Use unified configuration when it becomes available.
+   *
+   */
+  function init(config) {
+    var supported = config["views"];
+
+    for (var s in supported) if (supported.hasOwnProperty(s)) {
+      var obj = supported[s];
+      supportedViews[s] = new gadgets.views.View(s, obj.isOnlyVisible);
+      var aliases = obj.aliases || [];
+      for (var i = 0, alias; alias = aliases[i]; ++i) {
+        supportedViews[alias] = new gadgets.views.View(s, obj.isOnlyVisible);
+      }
+    }
+
+    var urlParams = gadgets.util.getUrlParameters();
+    // View parameters are passed as a single parameter.
+    if (urlParams["view-params"]) {
+      var tmpParams = gadgets.json.parse(
+          decodeURIComponent(urlParams["view-params"]));
+      if (tmpParams) {
+        params = tmpParams;
+      }
+    }
+    currentView = supportedViews[urlParams.view] || supportedViews["default"];
+  }
+
+  var requiredConfig = {
+    "default": new gadgets.config.LikeValidator({
+      "isOnlyVisible" : gadgets.config.BooleanValidator
+    })
+  };
+
+  gadgets.config.register("views", requiredConfig, init);
+
   return {
     requestNavigateTo : function(view, opt_params) {
-      // TODO: Actually implementing this is going to require gadgets.rpc or
-      // ifpc or something.
-      var prefs = new gadgets.Prefs();
-      var ifpcRelay = gadgets.util.getUrlParameters().parent || '';
-      gadgets.ifpc_.call("remote_iframe_" + prefs.getModuleId(),
-                         "requestNavigateTo",
-                        ["remote_iframe_" + prefs.getModuleId(),
-                          view.getName(),
-                         opt_params],
-                         ifpcRelay,
-                         null,
-                         '');
+      gadgets.rpc.call(
+          null, "requestNavigateTo", null, view.getName(), opt_params);
     },
 
     getCurrentView : function() {
@@ -70,35 +99,6 @@
 
     getParams : function() {
       return params;
-    },
-
-    /**
-     * Initializes views. Assumes that the current view is the "view"
-     * url parameter (or default if "view" isn't supported), and that
-     * all view parameters are in the form view-<name>
-     * TODO: Use unified configuration when it becomes available.
-     * @param {Map&lt;String, Boolean&gt;} supported The views you support,
-     *   where keys = name of the view and values = isOnlyVisible
-     */
-    init : function(supported) {
-      if (typeof supported["default"] === "undefined") {
-        throw new Error("default view required!");
-      }
-
-      for (var s in supported) if (supported.hasOwnProperty(s)) {
-        supportedViews[s] = new gadgets.views.View(s, supported[s]);
-      }
-
-      var urlParams = gadgets.util.getUrlParameters();
-      // View parameters are passed as a single parameter.
-      if (urlParams["view-params"]) {
-        var tmpParams = gadgets.json.parse(
-            decodeURIComponent(urlParams["view-params"]));
-        if (tmpParams) {
-          params = tmpParams;
-        }
-      }
-      currentView = supportedViews[urlParams.view] || supportedViews["default"];
     }
   };
 }();

Modified: incubator/shindig/trunk/java/gadgets/pom.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/pom.xml?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/pom.xml (original)
+++ incubator/shindig/trunk/java/gadgets/pom.xml Mon Feb 18 14:56:14 2008
@@ -61,7 +61,7 @@
               </includes>
             </resource>
           </webResources>
-         </configuration>  
+         </configuration>
       </plugin>
       <plugin>
           <groupId>org.apache.maven.plugins </groupId>
@@ -102,11 +102,72 @@
         <groupId>org.mortbay.jetty</groupId>
         <artifactId>maven-jetty-plugin</artifactId>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <!-- TODO: Replace this with the more generic javascript plugin that
+             allows the use of arbitrary compressor / compilers.
+             The maven-javascript-plugin does not seem to work.
+        -->
+        <!-- <groupId>net.sf.hammerfest</groupId> -->
+        <!-- <artifactId>maven-javascript-plugin</artifactId> -->
+        <groupId>net.sf.alchim</groupId>
+        <artifactId>yuicompressor-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>compress</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <nosuffix>true</nosuffix>
+          <excludes>
+            <!-- don't bother with other file types. -->
+            <exclude>**/*.xml</exclude>
+            <exclude>**/*.html</exclude>
+            <exclude>**/*.gif</exclude>
+            <exclude>**/*.jpeg</exclude>
+            <exclude>**/*.png</exclude>
+            <!-- Syndicator files are JSON, not javascript -->
+            <exclude>**/*syndicator.js</exclude>
+            <!-- open social files produce too many warnings -->
+            <exclude>**/opensocial-*/*</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
     </plugins>
     <resources>
       <resource>
         <targetPath>features</targetPath>
         <directory>../../features</directory>
+      </resource>
+      <resource>
+        <targetPath>syndicators/default</targetPath>
+        <directory>../../config</directory>
+        <includes>
+          <include>syndicator.js</include>
+        </includes>
+      </resource>
+      <resource>
+        <!-- duplicated here for the jar build. -->
+        <!-- TODO: Eliminate duplicate copies in WAR output -->
+        <!-- this is relative to the pom.xml directory -->
+        <directory>../../javascript/</directory>
+        <targetPath>files</targetPath>
+        <includes>
+          <include>**/*.*</include>
+        </includes>
       </resource>
     </resources>
   </build>

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BidiSubstituter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BidiSubstituter.java?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BidiSubstituter.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BidiSubstituter.java Mon Feb 18 14:56:14 2008
@@ -27,7 +27,7 @@
  */
 
 public class BidiSubstituter implements GadgetFeatureFactory {
-  private final static BidiSubstituterFeature feature
+  private final static GadgetFeature feature
       = new BidiSubstituterFeature();
 
   /**
@@ -38,7 +38,7 @@
   }
 }
 
-class BidiSubstituterFeature implements GadgetFeature {
+class BidiSubstituterFeature extends GadgetFeature {
 
   /**
    * Fetches a message bundle spec from the {@code GadgetSpec} for the
@@ -58,19 +58,13 @@
     return null;
   }
 
-  /** {@inheritDoc} */
-  public void prepare(GadgetView spec,
-                      GadgetContext context,
-                      Map<String, String> params) {
-    // Nothing here.
-  }
-
   /**
    * {@inheritDoc}
    */
-  public void process(Gadget gadget,
-                      GadgetContext context,
-                      Map<String, String> params) {
+  @Override
+  public void process(Gadget gadget, GadgetContext context,
+      Map<String, String> params) throws GadgetException {
+    super.process(gadget, context, params);
     Substitutions subst = gadget.getSubstitutions();
     Locale locale = context.getLocale();
     // Find an appropriate locale for the ltr flag.

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetContext.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetContext.java?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetContext.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetContext.java Mon Feb 18 14:56:14 2008
@@ -24,14 +24,9 @@
  * generic functionality such as retrieval of remote data and caching.
  */
 public class GadgetContext {
-  private final RemoteContentFetcher httpFetcher;
-  public RemoteContentFetcher getHttpFetcher() {
-    return httpFetcher;
-  }
-
-  private final GadgetDataCache<MessageBundle> messageBundleCache;
-  public GadgetDataCache<MessageBundle> getMessageBundleCache() {
-    return messageBundleCache;
+  private final GadgetServerConfigReader config;
+  public GadgetServerConfigReader getServerConfig() {
+    return config;
   }
 
   private final Locale locale;
@@ -43,7 +38,7 @@
   public RenderingContext getRenderingContext() {
     return renderingContext;
   }
-  
+
   private final ProcessingOptions options;
   public ProcessingOptions getOptions() {
     return options;
@@ -51,19 +46,16 @@
 
   /**
    * Creates a context for the current gadget.
-   * @param httpFetcher
-   * @param messageBundleCache
+   * @param config
    * @param locale
    * @param renderingContext
    * @param options
    */
-  public GadgetContext(RemoteContentFetcher httpFetcher,
-                       GadgetDataCache<MessageBundle> messageBundleCache,
+  public GadgetContext(GadgetServerConfigReader config,
                        Locale locale,
                        RenderingContext renderingContext,
                        ProcessingOptions options) {
-    this.httpFetcher = httpFetcher;
-    this.messageBundleCache = messageBundleCache;
+    this.config = config;
     this.locale = locale;
     this.renderingContext = renderingContext;
     this.options = options != null ? options : new ProcessingOptions();

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetException.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetException.java?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetException.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetException.java Mon Feb 18 14:56:14 2008
@@ -29,6 +29,7 @@
 
     // Configuration errors
     INVALID_PATH,
+    INVALID_CONFIG,
 
     // User-data related errors.
     INVALID_USER_DATA,
@@ -52,7 +53,7 @@
 
     // Caja error
     MALFORMED_FOR_SAFE_INLINING,
-    
+
     // View errors
     UNKNOWN_VIEW_SPECIFIED,
 

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeature.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeature.java?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeature.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetFeature.java Mon Feb 18 14:56:14 2008
@@ -17,6 +17,8 @@
  */
 package org.apache.shindig.gadgets;
 
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -42,9 +44,48 @@
  * and will <i>always</i> be instantiated this way. As such, it is recommended
  * not to define a constructor for a feature at all.
  */
-public interface GadgetFeature {
+public abstract class GadgetFeature {
+
+  /**
+   * Performs any pre-processing required to handle this feature.
+   * By default this does nothing.
+   *
+   * @param gadget
+   * @param context
+   * @param params
+   * @throws GadgetException
+   */
   public void prepare(GadgetView gadget, GadgetContext context,
-                      Map<String, String> params) throws GadgetException;
+                      Map<String, String> params) throws GadgetException {
+    // by default we do nothing, we just don't want to force all features
+    // to implement this.
+  }
+
+  /**
+   * Performs post-processing required to handle this feature.
+   * By default this also does nothing.
+   *
+   * @param gadget
+   * @param context
+   * @param params
+   * @throws GadgetException
+   */
   public void process(Gadget gadget, GadgetContext context,
-                      Map<String, String> params) throws GadgetException;
+      Map<String, String> params) throws GadgetException {
+    // we do nothing here as well.
+  }
+
+  /**
+   * This is used by various consumers to retrieve all javascript libraries
+   * that this feature uses without necessarily processing them.
+   * This is primarily used by features that simply pass-through libraries.
+   *
+   * @param context
+   * @param options
+   * @return A list of all libraries needed by this feature for the request.
+   */
+  public List<JsLibrary> getJsLibraries(RenderingContext context,
+                                        ProcessingOptions options) {
+    return Collections.emptyList();
+  }
 }

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=628908&r1=628907&r2=628908&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 Mon Feb 18 14:56:14 2008
@@ -40,6 +40,10 @@
   private final Map<String, Entry> features = new HashMap<String, Entry>();
   private final Map<String, Entry> core =  new HashMap<String, Entry>();
 
+  // Caches the transitive dependencies to enable faster lookups.
+  private final Map<Set<String>, Set<Entry>> transitiveDeps
+      = new HashMap<Set<String>, Set<Entry>>();
+
   // Constants used for internal feature names.
   private final static String FEAT_MSG_BUNDLE = "core.msgbundlesubst";
   private final static String FEAT_BIDI = "core.bidisubst";
@@ -169,22 +173,36 @@
   public boolean getIncludedFeatures(Set<String> needed,
                                      Set<Entry> resultsFound,
                                      Set<String> resultsMissing) {
-    resultsFound.clear();
-    resultsMissing.clear();
     if (needed.size() == 0) {
       // Shortcut for gadgets that don't have any explicit dependencies.
       resultsFound.addAll(core.values());
       return true;
     }
-    for (String featureName : needed) {
-      Entry entry = features.get(featureName);
-      if (entry == null) {
-        resultsMissing.add(featureName);
-      } else {
-        addEntryToSet(resultsFound, entry);
+    // We use the cache only for situations where all needed are available.
+    // if any are missing, the result won't be cached.
+    Set<Entry> cache = transitiveDeps.get(needed);
+    if (cache != null) {
+      resultsFound.addAll(cache);
+      return true;
+    } else {
+      for (String featureName : needed) {
+        Entry entry = features.get(featureName);
+        if (entry == null) {
+          resultsMissing.add(featureName);
+        } else {
+          addEntryToSet(resultsFound, entry);
+        }
+      }
+
+      if (resultsMissing.size() == 0) {
+        // Store to cache
+        transitiveDeps.put(
+            Collections.unmodifiableSet(new HashSet<String>(needed)),
+            Collections.unmodifiableSet(new HashSet<Entry>(resultsFound)));
+        return true;
       }
     }
-    return resultsMissing.size() == 0;
+    return false;
   }
 
   /**
@@ -206,15 +224,6 @@
    */
   Entry getEntry(String name) {
     return features.get(name);
-  }
-
-  public static class NoOpFeature implements GadgetFeature {
-    public void prepare(GadgetView gadget, GadgetContext context,
-        Map<String, String> params) {
-    }
-    public void process(Gadget gadget, GadgetContext context,
-        Map<String, String> params) {
-    }
   }
 
   /**

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=628908&r1=628907&r2=628908&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 Mon Feb 18 14:56:14 2008
@@ -83,8 +83,7 @@
       throws GadgetProcessException {
 
     // Queue/tree of all jobs to be run for successful processing
-    GadgetContext gc = new GadgetContext(config.getContentFetcher(),
-                                         config.getMessageBundleCache(),
+    GadgetContext gc = new GadgetContext(config,
                                          locale,
                                          rctx,
                                          options);

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfig.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfig.java?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfig.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfig.java Mon Feb 18 14:56:14 2008
@@ -77,4 +77,9 @@
     this.gadgetBlacklist = gadgetBlacklist;
     return this;
   }
+
+  public GadgetServerConfig setSyndicatorConfig(SyndicatorConfig config) {
+    syndicatorConfig = config;
+    return this;
+  }
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfigReader.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfigReader.java?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfigReader.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServerConfigReader.java Mon Feb 18 14:56:14 2008
@@ -67,16 +67,27 @@
     return gadgetBlacklist;
   }
 
+  protected SyndicatorConfig syndicatorConfig;
+
+  public SyndicatorConfig getSyndicatorConfig() {
+    if (syndicatorConfig == null) {
+      return SyndicatorConfig.EMPTY;
+    }
+    return syndicatorConfig;
+  }
+
   /**
    * Copies all fields from {@code base} into this instance.
    * @param base
    */
   public void copyFrom(GadgetServerConfigReader base) {
+    // We use the getters here just in case any methods were overridden.
     executor = base.getExecutor();
     featureRegistry = base.getFeatureRegistry();
     contentFetcher = base.getContentFetcher();
     specCache = base.getSpecCache();
     messageBundleCache = base.getMessageBundleCache();
     gadgetBlacklist = base.getGadgetBlacklist();
+    syndicatorConfig = base.getSyndicatorConfig();
   }
 }

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=628908&r1=628907&r2=628908&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 Mon Feb 18 14:56:14 2008
@@ -17,31 +17,23 @@
  */
 package org.apache.shindig.gadgets;
 
-import org.apache.shindig.util.InputStreamConsumer;
+import org.apache.shindig.util.ResourceLoader;
 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;
 import org.xml.sax.SAXException;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
-import java.io.InputStream;
-import java.net.JarURLConnection;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.ArrayList;
-import java.util.Enumeration;
+import java.io.StringReader;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
 import java.util.logging.Logger;
 
 import javax.xml.parsers.DocumentBuilderFactory;
@@ -61,6 +53,8 @@
  */
 public class JsFeatureLoader {
 
+  private static final String FEATURE_FILE_NAME = "feature.xml";
+
   private static final Logger logger
       = Logger.getLogger("org.apache.shindig.gadgets");
 
@@ -81,13 +75,22 @@
   public List<GadgetFeatureRegistry.Entry> loadFeatures(String path,
       GadgetFeatureRegistry registry) throws GadgetException {
     Map<String, ParsedFeature> deps = new HashMap<String, ParsedFeature>();
-    if (path.startsWith("res://")) {
-      logger.info("Loading resources from: " + path);
-      loadResources(new String[]{path.substring(6)}, deps);
-    } else {
-      logger.info("Loading files from: " + path);
-      File file = new File(path);
-      loadFiles(new File[]{file}, deps);
+    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);
+        } else {
+          loadResources(new String[]{path}, deps);
+        }
+      } else {
+        logger.info("Loading files from: " + path);
+        File file = new File(path);
+        loadFiles(new File[]{file}, deps);
+      }
+    } catch (IOException e) {
+      throw new GadgetException(GadgetException.Code.INVALID_PATH, e);
     }
 
     List<GadgetFeatureRegistry.Entry> entries
@@ -117,7 +120,7 @@
     for (File file : files) {
       if (file.isDirectory()) {
         loadFiles(file.listFiles(), features);
-      } else if ("feature.xml".equals(file.getName())) {
+      } else if (FEATURE_FILE_NAME.equals(file.getName())) {
         ParsedFeature feature = processFile(file);
         if (feature != null) {
           features.put(feature.name, feature);
@@ -128,110 +131,29 @@
 
   /**
    * Loads resources recursively.
-   * @param files The base paths to look for feature.xml
-   * @param features The set of all loaded features
+   * @param paths The base paths to look for feature.xml
+   * @param feats The set of all loaded features
    * @throws GadgetException
    */
-  private void loadResources(String[] files, Map<String, ParsedFeature> features)
+  private void loadResources(String[] paths, Map<String, ParsedFeature> feats)
       throws GadgetException {
-    ClassLoader cl = JsFeatureLoader.class.getClassLoader();
     try {
-      for (String file : files) {
-        file = file.trim();
-        if (file.endsWith(".txt")) {
-          loadResources(readResourceList(file), features);
-        } else if (file.endsWith("feature.xml")) {
-          ParsedFeature feature = processResource(file);
-          if (feature != null) {
-            features.put(feature.name, feature);
-          }
-        } else {
-          Enumeration<URL> mappedResources = cl.getResources(file);
-          while (mappedResources.hasMoreElements()) {
-            URL resourceUrl =  mappedResources.nextElement();
-            if ("file".equals(resourceUrl.getProtocol())) {
-              File f = new File(resourceUrl.toURI());
-              loadFiles(new File[]{f}, features);
-            } else {
-              URLConnection urlConnection = resourceUrl.openConnection();
-              List<String> featurePaths = new ArrayList<String>();
-              if (urlConnection instanceof JarURLConnection) {
-                JarURLConnection jarUrlConn = (JarURLConnection)urlConnection;
-                JarFile jar = jarUrlConn.getJarFile();
-
-                Enumeration<JarEntry> jarEntries = jar.entries();
-                while (jarEntries.hasMoreElements()) {
-                  JarEntry jarEntry =  jarEntries.nextElement();
-                  if (jarEntry.getName().startsWith(file) &&
-                      jarEntry.getName().endsWith("feature.xml")) {
-                    featurePaths.add(jarEntry.getName());
-                  }
-                }
-              }
-              for (String path : featurePaths) {
-                ParsedFeature feature = processResource(path);
-                if (feature != null) {
-                  features.put(feature.name, feature);
-                }
-              }
-            }
-          }
+      Map<String, String> contents
+          = ResourceLoader.getContent(paths, FEATURE_FILE_NAME);
+      for (Map.Entry<String, String> entry : contents.entrySet()) {
+        String parent = entry.getKey();
+        parent = parent.substring(0, parent.lastIndexOf(FEATURE_FILE_NAME));
+        ParsedFeature feature = parse(entry.getValue(), parent, true);
+        if (feature != null) {
+          feats.put(feature.name, feature);
         }
       }
-    } catch (IOException ioe) {
-      throw new GadgetException(GadgetException.Code.INVALID_PATH, ioe);
-    } catch (URISyntaxException use) {
-      throw new GadgetException(GadgetException.Code.INVALID_PATH, use);
+    } catch (IOException e) {
+      throw new GadgetException(GadgetException.Code.INVALID_PATH, e);
     }
   }
 
   /**
-   * @param path Location of the resource list.
-   * @return A list of resources from the list.
-   */
-  private String[] readResourceList(String path) throws IOException {
-    ClassLoader cl = JsFeatureLoader.class.getClassLoader();
-    InputStream is = cl.getResourceAsStream(path);
-    if (is == null) {
-      logger.warning("Unable to locate resource: " + path);
-      return new String[0];
-    } else {
-      String names = InputStreamConsumer.readToString(is);
-      if (names == null) {
-        logger.warning("Unable to load resource: " + path);
-        return new String[0];
-      }
-      return names.split("\n");
-    }
-  }
-
-  /**
-   * Loads a single feature from a resource.
-   *
-   * If the resource can't be loaded, an error will be printed but no exception
-   * will be thrown.
-   *
-   * @param name The resource that contains the feature description.
-   * @return The parsed feature.
-   */
-  private ParsedFeature processResource(String name) {
-    logger.info("Loading resource: " + name);
-    ParsedFeature feature = null;
-    try {
-      ClassLoader cl = JsFeatureLoader.class.getClassLoader();
-      InputStream is = cl.getResourceAsStream(name);
-      if (is != null) {
-        int lastSlash = name.lastIndexOf('/');
-        String base = (lastSlash == -1) ? name : name.substring(0, lastSlash + 1);
-        feature = parse(is, base, true);
-      }
-    } catch (GadgetException ge) {
-      logger.warning("Failed to load resource: " + name);
-    }
-    return feature;
-  }
-
-  /**
    * Loads a single feature from a file.
    *
    * If the file can't be loaded, an error will be generated but no exception
@@ -245,11 +167,12 @@
     ParsedFeature feature = null;
     if (file.canRead()) {
       try {
-        feature = parse(
-            new FileInputStream(file), file.getParent() + '/', false);
+        feature = parse(ResourceLoader.getContent(file),
+                        file.getParent() + '/',
+                        false);
       } catch (IOException e) {
         logger.warning("Error reading file: " + file.getAbsolutePath());
-      } catch (GadgetException ge) {
+      } catch (GadgetException e) {
         logger.warning("Failed parsing file: " + file.getAbsolutePath());
       }
     } else {
@@ -268,8 +191,9 @@
    * @param all Map of all features that can be loaded during this operation.
    */
   private GadgetFeatureRegistry.Entry register(GadgetFeatureRegistry registry,
-      ParsedFeature feature, Set<String> registered,
-      Map<String, ParsedFeature> all) {
+                                               ParsedFeature feature,
+                                               Set<String> registered,
+                                               Map<String, ParsedFeature> all) {
     if (registered.contains(feature.name)) {
       return null;
     }
@@ -288,18 +212,19 @@
 
   /**
    * Parses the input into a dom tree.
-   * @param is
+   * @param xml
    * @param path The path the file was loaded from.
    * @param isResource True if the file was a resource.
    * @return A dom tree representing the feature.
    * @throws GadgetException
    */
-  private ParsedFeature parse(InputStream is, String path, boolean isResource)
+  private ParsedFeature parse(String xml, String path, boolean isResource)
       throws GadgetException {
 
     Document doc;
     try {
       DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+      InputSource is = new InputSource(new StringReader(xml));
       doc = factory.newDocumentBuilder().parse(is);
     } catch (SAXException e) {
       throw new GadgetException(GadgetException.Code.MALFORMED_XML_DOCUMENT, e);

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibrary.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibrary.java?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibrary.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibrary.java Mon Feb 18 14:56:14 2008
@@ -17,12 +17,10 @@
  */
 package org.apache.shindig.gadgets;
 
-import org.apache.shindig.util.InputStreamConsumer;
+import org.apache.shindig.util.ResourceLoader;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.util.logging.Logger;
 
 /**
@@ -131,10 +129,8 @@
           String.format("JsLibrary cannot be read: %s", fileName));
     }
 
-    FileInputStream fis = null;
     try {
-      fis = new FileInputStream(fileName);
-      return InputStreamConsumer.readToString(fis);
+      return ResourceLoader.getContent(file);
     } catch (IOException e) {
       throw new RuntimeException(
           String.format("Error reading file %s", fileName), e);
@@ -148,16 +144,10 @@
    */
   private static String loadResource(String name) {
      try {
-       InputStream stream =
-            JsLibrary.class.getClassLoader().getResourceAsStream(name);
-       if (stream == null) {
-         throw new RuntimeException(
-             String.format("Could not find resource %s", name));
-       }
-       return InputStreamConsumer.readToString(stream);
+       return ResourceLoader.getContent(name);
      } catch (IOException e) {
        throw new RuntimeException(
-           String.format("Could not find resource %s", name));
+           String.format("Could not find resource %s", name), e);
      }
   }
 

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=628908&r1=628907&r2=628908&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 Mon Feb 18 14:56:14 2008
@@ -17,6 +17,7 @@
  */
 package org.apache.shindig.gadgets;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
@@ -32,22 +33,12 @@
  *     new JsLibraryFeatureFactory(mylib));
  */
 public class JsLibraryFeatureFactory implements GadgetFeatureFactory {
-  private JsLibraryFeature feature;
+  private final JsLibraryFeature feature;
 
   public GadgetFeature create() {
     return feature;
   }
 
-  /**
-   * @param context
-   * @return A list of all JS libraries used by this feature
-   */
-  public List<JsLibrary> getLibraries(RenderingContext context) {
-    return context == RenderingContext.GADGET ?
-        feature.gadgetLibraries :
-        feature.containerLibraries;
-  }
-
   public JsLibraryFeatureFactory(JsLibrary gadgetLibrary,
                                  JsLibrary containerLibrary) {
     this.feature = new JsLibraryFeature(gadgetLibrary, containerLibrary);
@@ -56,9 +47,12 @@
                                  List<JsLibrary> containerLibraries) {
     this.feature = new JsLibraryFeature(gadgetLibraries, containerLibraries);
   }
+  protected JsLibraryFeatureFactory() {
+    feature = null;
+  }
 }
 
-class JsLibraryFeature implements GadgetFeature {
+class JsLibraryFeature extends GadgetFeature {
   List<JsLibrary> containerLibraries;
   List<JsLibrary> gadgetLibraries;
 
@@ -72,17 +66,15 @@
     if (gadgetLibrary == null) {
       gadgetLibraries = Collections.emptyList();
     } else {
-      gadgetLibraries = new LinkedList<JsLibrary>();
-      gadgetLibraries.add(gadgetLibrary);
-      gadgetLibraries = Collections.unmodifiableList(gadgetLibraries);
+      gadgetLibraries
+          = Collections.unmodifiableList(Arrays.asList(gadgetLibrary));
     }
 
     if (containerLibrary == null) {
       containerLibraries = Collections.emptyList();
     } else {
-      containerLibraries = new LinkedList<JsLibrary>();
-      containerLibraries.add(containerLibrary);
-      containerLibraries = Collections.unmodifiableList(containerLibraries);
+      containerLibraries
+          = Collections.unmodifiableList(Arrays.asList(containerLibrary));
     }
   }
 
@@ -96,33 +88,39 @@
     if (gLibraries == null) {
       gadgetLibraries = Collections.emptyList();
     } else {
-      gadgetLibraries = new LinkedList<JsLibrary>();
-      gadgetLibraries.addAll(gLibraries);
-      gadgetLibraries = Collections.unmodifiableList(gadgetLibraries);
+      gadgetLibraries
+          = Collections.unmodifiableList(new LinkedList<JsLibrary>(gLibraries));
     }
 
     if (cLibraries == null) {
       containerLibraries = Collections.emptyList();
     } else {
-      containerLibraries = new LinkedList<JsLibrary>();
-      containerLibraries.addAll(cLibraries);
-      containerLibraries = Collections.unmodifiableList(containerLibraries);
+      containerLibraries
+        = Collections.unmodifiableList(new LinkedList<JsLibrary>(cLibraries));
     }
   }
 
   /**
    * {@inheritDoc}
    */
-  public void prepare(GadgetView gadget, GadgetContext context,
-      Map<String, String> params) {
-    // Do nothing.
+  @Override
+  public List<JsLibrary> getJsLibraries(RenderingContext context,
+                                        ProcessingOptions options) {
+    if (context == RenderingContext.GADGET) {
+      return gadgetLibraries;
+    } else if (context == RenderingContext.CONTAINER) {
+      return containerLibraries;
+    }
+    return Collections.emptyList();
   }
 
   /**
    * {@inheritDoc}
    */
+  @Override
   public void process(Gadget gadget, GadgetContext context,
-      Map<String, String> params) {
+      Map<String, String> params) throws GadgetException {
+    super.process(gadget, context, params);
     List<JsLibrary> libraries;
     if (context.getRenderingContext() == RenderingContext.GADGET) {
       libraries = gadgetLibraries;

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/MessageBundleSubstituter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/MessageBundleSubstituter.java?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/MessageBundleSubstituter.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/MessageBundleSubstituter.java Mon Feb 18 14:56:14 2008
@@ -38,7 +38,7 @@
   }
 }
 
-class MessageBundleSubstituterFeature implements GadgetFeature {
+class MessageBundleSubstituterFeature extends GadgetFeature {
   private static final MessageBundleParser parser
       = new MessageBundleParser();
 
@@ -65,8 +65,10 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void prepare(GadgetView gadget, GadgetContext context,
                       Map<String, String> params) throws GadgetException {
+    super.prepare(gadget, context, params);
     Locale locale = context.getLocale();
     GadgetSpec.LocaleSpec localeData = getLocaleSpec(gadget, locale);
     if (localeData == null) {
@@ -79,15 +81,17 @@
       localeData = getLocaleSpec(gadget, new Locale("all", "all"));
     }
 
+    GadgetServerConfigReader config = context.getServerConfig();
+
     if (localeData != null) {
       URI uri = localeData.getURI();
       if (uri != null) {
         // We definitely need a bundle, now we need to fetch it.
-        bundle = context.getMessageBundleCache().get(uri.toString());
+        bundle = config.getMessageBundleCache().get(uri.toString());
         if (bundle == null) {
           RemoteContent data = null;
-          data = context.getHttpFetcher().fetch(new RemoteContentRequest(uri),
-                                                context.getOptions());
+          data = config.getContentFetcher().fetch(new RemoteContentRequest(uri),
+                                                  context.getOptions());
           if (data.getHttpStatusCode() != RemoteContent.SC_OK) {
             throw new GadgetException(
                 GadgetException.Code.FAILED_TO_RETRIEVE_CONTENT,
@@ -95,7 +99,7 @@
                               uri.toString()));
           }
           bundle = parser.parse(data.getResponseAsString());
-          context.getMessageBundleCache().put(uri.toString(), bundle);
+          config.getMessageBundleCache().put(uri.toString(), bundle);
         }
       }
     }
@@ -104,8 +108,10 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public void process(Gadget gadget, GadgetContext context,
-                      Map<String, String> params) {
+                      Map<String, String> params) throws GadgetException {
+    super.process(gadget, context, params);
     StringBuilder js = new StringBuilder();
     int moduleId = gadget.getId().getModuleId();
     Locale locale = context.getLocale();

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/ModuleSubstituter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/ModuleSubstituter.java?rev=628908&r1=628907&r2=628908&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/ModuleSubstituter.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/ModuleSubstituter.java Mon Feb 18 14:56:14 2008
@@ -33,22 +33,15 @@
   }
 }
 
-class ModuleSubstituterFeature implements GadgetFeature {
-
-  /**
-   * {@inheritDoc}
-   */
-  public void prepare(GadgetView gadget, GadgetContext context,
-      Map<String, String> params) {
-    // TODO Auto-generated method stub
-
-  }
+class ModuleSubstituterFeature extends GadgetFeature {
 
   /**
    * {@inheritDoc}
    */
+  @Override
   public void process(Gadget gadget, GadgetContext context,
-      Map<String, String> params) {
+      Map<String, String> params) throws GadgetException {
+    super.process(gadget, context, params);
     gadget.getSubstitutions().addSubstitution(Substitutions.Type.MODULE, "ID",
         Integer.toString(gadget.getId().getModuleId()));