You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by li...@apache.org on 2010/08/31 12:31:19 UTC

svn commit: r991146 - in /shindig/trunk: content/container/ content/samplecontainer/ extras/src/main/java/org/apache/shindig/extras/ extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/ extras/src/main/javascript/features-extras/pubsub-2/...

Author: lindner
Date: Tue Aug 31 10:31:19 2010
New Revision: 991146

URL: http://svn.apache.org/viewvc?rev=991146&view=rev
Log:
Patch from Javier Pedemonte | Incorporate OpenAjax Hub as Pub-Sub Mechanism for Shindig

Modified:
    shindig/trunk/content/container/sample-pubsub-2-publisher.xml
    shindig/trunk/content/container/sample-pubsub-2-subscriber.xml
    shindig/trunk/content/samplecontainer/samplecontainer.js
    shindig/trunk/extras/src/main/java/org/apache/shindig/extras/ShindigExtrasGuiceModule.java
    shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/OpenAjax-mashup.js
    shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/feature.xml
    shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/iframe.js
    shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/pubsub-2.js
    shindig/trunk/features/src/main/javascript/features/rpc/rpc.js
    shindig/trunk/features/src/main/javascript/features/shindig.container/feature.xml
    shindig/trunk/features/src/main/javascript/features/shindig.container/shindig-container.js

Modified: shindig/trunk/content/container/sample-pubsub-2-publisher.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/content/container/sample-pubsub-2-publisher.xml?rev=991146&r1=991145&r2=991146&view=diff
==============================================================================
--- shindig/trunk/content/container/sample-pubsub-2-publisher.xml (original)
+++ shindig/trunk/content/container/sample-pubsub-2-publisher.xml Tue Aug 31 10:31:19 2010
@@ -34,11 +34,9 @@
 <Content type="html">
 <![CDATA[
 <script>
-var g = gadgets.byId(__MODULE_ID__);
-
 function publish() {
   var message = Math.random();
-  g.PubSub.publish("org.apache.shindig.random-number", message);
+  gadgets.Hub.publish("org.apache.shindig.random-number", message);
   document.getElementById("output").innerHTML = message;
 }
 

Modified: shindig/trunk/content/container/sample-pubsub-2-subscriber.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/content/container/sample-pubsub-2-subscriber.xml?rev=991146&r1=991145&r2=991146&view=diff
==============================================================================
--- shindig/trunk/content/container/sample-pubsub-2-subscriber.xml (original)
+++ shindig/trunk/content/container/sample-pubsub-2-subscriber.xml Tue Aug 31 10:31:19 2010
@@ -35,10 +35,8 @@
 <script>
 var subId;
 
-var g = gadgets.byId(__MODULE_ID__);
-
 // Example of setting a parameter to the HubClient used by pubsub-2 feature.
-g.PubSubSettings.params.HubClient.onSecurityAlert = function(alertSource, alertType) {
+gadgets.HubSettings.params.HubClient.onSecurityAlert = function(alertSource, alertType) {
   alert("SECURITY ERROR!");
   window.location.href = "about:blank";
 };
@@ -50,11 +48,11 @@ function callback(topic, data, subscribe
 }
 
 function subscribe() {
-  subId = g.PubSub.subscribe("org.apache.shindig.random-number", callback);
+  subId = gadgets.Hub.subscribe("org.apache.shindig.random-number", callback);
 }
 
 function unsubscribe() {
-  g.PubSub.unsubscribe(subId);
+  gadgets.Hub.unsubscribe(subId);
   document.getElementById("output").innerHTML = "";
 }
 

Modified: shindig/trunk/content/samplecontainer/samplecontainer.js
URL: http://svn.apache.org/viewvc/shindig/trunk/content/samplecontainer/samplecontainer.js?rev=991146&r1=991145&r2=991146&view=diff
==============================================================================
--- shindig/trunk/content/samplecontainer/samplecontainer.js (original)
+++ shindig/trunk/content/samplecontainer/samplecontainer.js Tue Aug 31 10:31:19 2010
@@ -90,10 +90,15 @@ shindig.samplecontainer = {};
   }
 
   SampleContainerGadget = function(opt_params) {
-    shindig.IfrGadget.call(this, opt_params);
+    shindig.BaseIfrGadget.call(this, opt_params);
+
+    // mix-in IfrGadget functions
+    for (var name in shindig.IfrGadget) if (shindig.IfrGadget.hasOwnProperty(name)) {
+      SampleContainerGadget[name] = shindig.IfrGadget[name];
+    }
   };
 
-  SampleContainerGadget.inherits(shindig.IfrGadget);
+  SampleContainerGadget.inherits(shindig.BaseIfrGadget);
 
   SampleContainerGadget.prototype.getAdditionalParams = function() {
     var params = '';

Modified: shindig/trunk/extras/src/main/java/org/apache/shindig/extras/ShindigExtrasGuiceModule.java
URL: http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/java/org/apache/shindig/extras/ShindigExtrasGuiceModule.java?rev=991146&r1=991145&r2=991146&view=diff
==============================================================================
--- shindig/trunk/extras/src/main/java/org/apache/shindig/extras/ShindigExtrasGuiceModule.java (original)
+++ shindig/trunk/extras/src/main/java/org/apache/shindig/extras/ShindigExtrasGuiceModule.java Tue Aug 31 10:31:19 2010
@@ -34,7 +34,7 @@ public class ShindigExtrasGuiceModule ex
 
   protected void configureExtraFeatures() {
     // This is how you add search paths for features.
-    Multibinder<String> featureBinder = Multibinder.newSetBinder(binder(), String.class, Names.named("org.apache.shindig.features")); 
+    Multibinder<String> featureBinder = Multibinder.newSetBinder(binder(), String.class, Names.named("org.apache.shindig.features-extended")); 
     featureBinder.addBinding().toInstance("res://features-extras/features.txt");
   }
 }

Modified: shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/OpenAjax-mashup.js
URL: http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/OpenAjax-mashup.js?rev=991146&r1=991145&r2=991146&view=diff
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/OpenAjax-mashup.js (original)
+++ shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/OpenAjax-mashup.js Tue Aug 31 10:31:19 2010
@@ -28,7 +28,7 @@ OpenAjax.hub = function() {
 
     return /** @scope OpenAjax.hub */ {
         implementer: "http://openajax.org",
-        implVersion: "2.0.3",
+        implVersion: "2.0.4",
         specVersion: "2.0",
         implExtraData: {},
         libraries: libs,

Modified: shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/feature.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/feature.xml?rev=991146&r1=991145&r2=991146&view=diff
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/feature.xml (original)
+++ shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/feature.xml Tue Aug 31 10:31:19 2010
@@ -17,7 +17,7 @@ KIND, either express or implied. See the
 specific language governing permissions and limitations under the License.
 -->
 <feature>
-  <name>org.openajax.hub-2.0.3</name>
+  <name>org.openajax.hub-2.0.4</name>
   <dependency>rpc</dependency>
   <gadget>
     <script src="OpenAjax-mashup.js"/>

Modified: shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/iframe.js
URL: http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/iframe.js?rev=991146&r1=991145&r2=991146&view=diff
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/iframe.js (original)
+++ shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/iframe.js Tue Aug 31 10:31:19 2010
@@ -26,10 +26,10 @@ OpenAjax.gadgets.rpctx = OpenAjax.gadget
     // For now, we only use "oaaConfig" for the global "gadgets" object.  If the "gadgets" global
     // already exists, then there is no reason to check for "oaaConfig".  In the future, if we use
     // "oaaConfig" for other purposes, we'll need to remove the check for "!window.gadgets".
-    if (!window.gadgets) {
+    if (typeof gadgets === 'undefined') {
         // "oaaConfig" can be specified as a global object.  If not found, then look for it as an
         // attribute on the script line for the OpenAjax Hub JS file.
-        if (!window.oaaConfig) {
+        if (typeof oaaConfig === 'undefined') {
             var scripts = document.getElementsByTagName("script");
             // match "OpenAjax-mashup.js", "OpenAjaxManagedHub-all*.js", "OpenAjaxManagedHub-core*.js"
             var reHub = /openajax(?:managedhub-(?:all|core).*|-mashup)\.js$/i;
@@ -44,7 +44,7 @@ OpenAjax.gadgets.rpctx = OpenAjax.gadget
                     var config = scripts[i].getAttribute( "oaaConfig" );
                     if ( config ) {
                         try {
-                            window.oaaConfig = eval( "({ " + config + " })" );
+                            oaaConfig = eval( "({ " + config + " })" );
                         } catch (e) {}
                     }
                     break;
@@ -52,8 +52,8 @@ OpenAjax.gadgets.rpctx = OpenAjax.gadget
             }
         }
         
-        if (window.oaaConfig && window.oaaConfig.gadgetsGlobal) {
-            window.gadgets = OpenAjax.gadgets;
+        if (typeof oaaConfig !== 'undefined' && oaaConfig.gadgetsGlobal) {
+            gadgets = OpenAjax.gadgets;
         }
     }
 })();
@@ -529,13 +529,16 @@ OpenAjax.hub.IframeHubClient = function(
         }
         
         OpenAjax.hub.IframeContainer._rpcRouter.add( "..", this );
-//        securityToken = generateSecurityToken( params, scope, log );    // XXX still necessary?
+// XXX The RPC layer initializes immediately on load, in the child (IframeHubClient). So it is too
+//    late here to specify a security token for the RPC layer.  At the moment, only the NIX
+//    transport requires a child token (IFPC [aka FIM] is not supported).
+//        securityToken = generateSecurityToken( params, scope, log );
 
         var internalID = OpenAjax.gadgets.rpc.RPC_ID;
         if ( ! internalID ) {
             throw new Error( OpenAjax.hub.Error.WrongProtocol );
         }
-        clientID = decodeURIComponent( internalID.substr( internalID.indexOf("_") + 1 ) );
+        clientID = internalID.substr( internalID.indexOf("_") + 1 );
     };
     
   /*** HubClient interface ***/
@@ -802,7 +805,6 @@ OpenAjax.hub.IframeContainer._rpcRouter 
                     return;
                 }
                 
-                id = encodeURIComponent( id );
                 do {
                     // a client with the specified ID already exists on this page;
                     // create a unique ID
@@ -818,9 +820,9 @@ OpenAjax.hub.IframeContainer._rpcRouter 
                 securityCallback: onSecurityAlert
             });
 
-            rpcErrorsToOAA[ OpenAjax.gadgets.rpc.LOAD_TIMEOUT ] = OpenAjax.hub.SecurityAlert.LoadTimeout;
-            rpcErrorsToOAA[ OpenAjax.gadgets.rpc.FRAME_PHISH ] = OpenAjax.hub.SecurityAlert.FramePhish;
-            rpcErrorsToOAA[ OpenAjax.gadgets.rpc.FORGED_MSG ] = OpenAjax.hub.SecurityAlert.ForgedMsg;
+            rpcErrorsToOAA[ OpenAjax.gadgets.rpc.SEC_ERROR_LOAD_TIMEOUT ] = OpenAjax.hub.SecurityAlert.LoadTimeout;
+            rpcErrorsToOAA[ OpenAjax.gadgets.rpc.SEC_ERROR_FRAME_PHISH ] = OpenAjax.hub.SecurityAlert.FramePhish;
+            rpcErrorsToOAA[ OpenAjax.gadgets.rpc.SEC_ERROR_FORGED_MSG ] = OpenAjax.hub.SecurityAlert.ForgedMsg;
             
             this.add = _add;
             return _add( id, receiver );
@@ -836,7 +838,7 @@ var rpcErrorsToOAA = {};
 
 ////////////////////////////////////////////////////////////////////////////////
 
-function generateSecurityToken( params, scope, log, overrideTokenLength ) {
+function generateSecurityToken( params, scope, log ) {
     if ( ! OpenAjax.hub.IframeContainer._prng ) {
         // create pseudo-random number generator with a default seed
         var seed = new Date().getTime() + Math.random() + document.cookie;
@@ -854,7 +856,7 @@ function generateSecurityToken( params, 
         }
     }
     
-    var tokenLength = overrideTokenLength || (p && p.tokenLength) || 6;
+    var tokenLength = (p && p.tokenLength) || 6;
     return OpenAjax.hub.IframeContainer._prng.nextRandomB64Str( tokenLength );
 }
 

Modified: shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/pubsub-2.js
URL: http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/pubsub-2.js?rev=991146&r1=991145&r2=991146&view=diff
==============================================================================
--- shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/pubsub-2.js (original)
+++ shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/pubsub-2.js Tue Aug 31 10:31:19 2010
@@ -21,19 +21,19 @@
  * 
  * Uses OpenAjax Hub in order to do pubsub.  Simple case is to do the following:
  *    
- *    var gadget = gadgets.byId(__MODULE_ID__);
- *    gadget.PubSub.subscribe(topic, callback);
- *    ...
- *    gadget.PubSub.publish(topic2, message);
+ *    gadgets.util.registerOnLoadHandler(function() {
+ *      gadgets.Hub.subscribe(topic, callback);
+ *      // OR
+ *      gadgets.Hub.publish(topic2, message);
+ *    });
  * 
- * The <gadget instance>.PubSub object implements the OpenAjax.hub.HubClient
- * interface.
+ * The gadgets.Hub object implements the OpenAjax.hub.HubClient interface.
  * 
  * By default, a HubClient is instantiated automatically by the pubsub-2 code.
  * If the gadget wants to provide params to the HubClient constructor, it can
- * do so by setting values on <gadget instance>.PubSubSettings object:
+ * do so by setting values on gadgets.HubSettings object:
  * 
- *     <gadget instance>.PubSubSettings = {
+ *     gadgets.HubSettings = {
  *         // Parameters object for HubClient constructor.
  *         // @see http://openajax.org/member/wiki/OpenAjax_Hub_2.0_Specification_Managed_Hub_APIs#OpenAjax.hub.HubClient_constructor
  *         // @see http://openajax.org/member/wiki/OpenAjax_Hub_2.0_Specification_Managed_Hub_APIs#OpenAjax.hub.IframeHubClient_constructor
@@ -46,19 +46,15 @@
  * 
  * For example, to set a security alert callback:
  * 
- *     <gadget instance>.PubSubSettings.params.HubClient.onSecurityCallback =
+ *     gadgets.HubSettings.params.HubClient.onSecurityCallback =
  *             function(alertSource, alertType) { ... };
  * 
  * @see http://openajax.org/member/wiki/OpenAjax_Hub_2.0_Specification_Managed_Hub_APIs#OpenAjax.hub.HubClient
  */
 
 (function() {
-    var params = gadgets.util.getUrlParameters();
-    var moduleId = params.mid || 0;
-    var gadgetInstance = gadgets.byId(moduleId);
-    
     // Create a pubsub settings object
-    gadgetInstance.PubSubSettings = {
+    gadgets.HubSettings = {
         // Set default HubClient constructor params object
         params: {
             HubClient: {
@@ -66,27 +62,26 @@
                     alert( "Gadget stopped attempted security breach: " + alertType );
                     // Forces container to see Frame Phish alert and probably close this gadget
                     window.location.href = "about:blank"; 
-                },
-                scope: gadgetInstance
+                }
             },
             IframeHubClient: {}
         }
     };
-    if (params.forcesecure) {
-        gadgetInstance.PubSubSettings.params.IframeHubClient.requireParentVerifiable = true;
+    if (gadgets.util.getUrlParameters().forcesecure) {
+        gadgets.HubSettings.params.IframeHubClient.requireParentVerifiable = true;
     }
     
     // Register an onLoad handler
     gadgets.util.registerOnLoadHandler(function() {
         try {
             // Create the HubClient.
-            gadgetInstance.PubSub = new OpenAjax.hub.IframeHubClient(gadgetInstance.PubSubSettings.params);
+            gadgets.Hub = new OpenAjax.hub.IframeHubClient(gadgets.HubSettings.params);
             
             // Connect to the ManagedHub
-            gadgetInstance.PubSub.connect(gadgetInstance.PubSubSettings.onConnect); 
+            gadgets.Hub.connect(gadgets.HubSettings.onConnect); 
         } catch(e) {
             // TODO: error handling should be consistent with other OS gadget initialization error handling
-            gadgets.error("ERROR creating or connecting IframeHubClient in gadgets.pubsub [" + e.message + "]");
+            gadgets.error("ERROR creating or connecting IframeHubClient in gadgets.Hub [" + e.message + "]");
         }
     });
 })();

Modified: shindig/trunk/features/src/main/javascript/features/rpc/rpc.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/rpc/rpc.js?rev=991146&r1=991145&r2=991146&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/rpc/rpc.js (original)
+++ shindig/trunk/features/src/main/javascript/features/rpc/rpc.js Tue Aug 31 10:31:19 2010
@@ -204,6 +204,8 @@ gadgets.rpc = function() {
   // ("unload" event).
   //  NOTE: The use of the "unload" handler here and for the relay iframe
   // prevents the use of the in-memory page cache in modern browsers.
+  // See: https://developer.mozilla.org/en/using_firefox_1.5_caching
+  // See: http://webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/
   var mainPageUnloading = false,
       hookedUnload = false;
   
@@ -657,7 +659,7 @@ gadgets.rpc = function() {
    * @param {string} targetId
    * @param {string=} opt_receiverurl
    * @param {string=} opt_authtoken
-   * @param {string=} opt_forcesecure
+   * @param {boolean=} opt_forcesecure
    */
   function setupReceiver(targetId, opt_receiverurl, opt_authtoken, opt_forcesecure) {
     if (targetId === '..') {
@@ -802,10 +804,6 @@ gadgets.rpc = function() {
       // Attempt to make call via a cross-domain transport.
       // Retrieve the transport for the given target - if one
       // target is misconfigured, it won't affect the others.
-      // TODO Since 'transport' is always set (on load of rpc.js), channel will never
-      //    be null (and earlyRpcQueue will never be used).  Only use
-      //    receiverTx[targetId].
-      //      var channel = receiverTx[targetId] ? receiverTx[targetId] : transport;
       var channel = receiverTx[targetId];
 
       if (!channel) {
@@ -991,9 +989,9 @@ gadgets.rpc = function() {
 
     RPC_ID: rpcId,
     
-    LOAD_TIMEOUT: LOAD_TIMEOUT,
-    FRAME_PHISH: FRAME_PHISH,
-    FORGED_MSG : FORGED_MSG
+    SEC_ERROR_LOAD_TIMEOUT: LOAD_TIMEOUT,
+    SEC_ERROR_FRAME_PHISH: FRAME_PHISH,
+    SEC_ERROR_FORGED_MSG : FORGED_MSG
   };
 }();
 

Modified: shindig/trunk/features/src/main/javascript/features/shindig.container/feature.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/shindig.container/feature.xml?rev=991146&r1=991145&r2=991146&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/shindig.container/feature.xml (original)
+++ shindig/trunk/features/src/main/javascript/features/shindig.container/feature.xml Tue Aug 31 10:31:19 2010
@@ -27,6 +27,7 @@ A map of view names to view attributes. 
   <dependency>globals</dependency>
   <dependency>rpc</dependency>
   <dependency>osapi</dependency>
+  <dependency>shindig.uri.ext</dependency>
   <container>
     <script src="util.js"/>
     <script src="cookies.js"/>

Modified: shindig/trunk/features/src/main/javascript/features/shindig.container/shindig-container.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/shindig.container/shindig-container.js?rev=991146&r1=991145&r2=991146&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/shindig.container/shindig-container.js (original)
+++ shindig/trunk/features/src/main/javascript/features/shindig.container/shindig-container.js Tue Aug 31 10:31:19 2010
@@ -46,7 +46,11 @@ shindig.callAsyncAndJoin = function(func
     // we need a wrapper here because i changes and we need one index
     // variable per closure
     var wrapper = function(index) {
-      functions[index].call(opt_this, function(result) {
+      var fn = functions[index];
+      if (typeof fn === 'string') {
+        fn = opt_this[fn];
+      }
+      fn.call(opt_this, function(result) {
         results[index] = result;
         if (--pending === 0) {
           continuation(results);
@@ -418,15 +422,15 @@ shindig.Gadget.prototype.render = functi
     var gadget = this;
     this.getContent(function(content) {
       chrome.innerHTML = content;
-      window.frames[gadget.getIframeId()].location = gadget.getIframeUrl();
+      gadget.finishRender(chrome);
     });
   }
 };
 
 shindig.Gadget.prototype.getContent = function(continuation) {
   shindig.callAsyncAndJoin([
-      this.getTitleBarContent, this.getUserPrefsDialogContent,
-      this.getMainContent], function(results) {
+      'getTitleBarContent', 'getUserPrefsDialogContent',
+      'getMainContent'], function(results) {
         continuation(results.join(''));
       }, this);
 };
@@ -458,6 +462,10 @@ shindig.Gadget.prototype.getMainContent 
   throw Error(shindig.errors.SUBCLASS_RESPONSIBILITY);
 };
 
+shindig.Gadget.prototype.finishRender = function(chrome) {
+  throw Error(shindig.errors.SUBCLASS_RESPONSIBILITY);
+};
+
 /*
  * Gets additional parameters to append to the iframe url
  * Override this method if you need any custom params.
@@ -470,32 +478,33 @@ shindig.Gadget.prototype.getAdditionalPa
 // ---------
 // IfrGadget
 
-shindig.IfrGadget = function(opt_params) {
+shindig.BaseIfrGadget = function(opt_params) {
   shindig.Gadget.call(this, opt_params);
   this.serverBase_ = '/gadgets/'; // default gadget server
+  this.queryIfrGadgetType_();
 };
 
-shindig.IfrGadget.inherits(shindig.Gadget);
+shindig.BaseIfrGadget.inherits(shindig.Gadget);
 
-shindig.IfrGadget.prototype.GADGET_IFRAME_PREFIX_ = 'remote_iframe_';
+shindig.BaseIfrGadget.prototype.GADGET_IFRAME_PREFIX_ = 'remote_iframe_';
 
-shindig.IfrGadget.prototype.CONTAINER = 'default';
+shindig.BaseIfrGadget.prototype.CONTAINER = 'default';
 
-shindig.IfrGadget.prototype.cssClassGadget = 'gadgets-gadget';
-shindig.IfrGadget.prototype.cssClassTitleBar = 'gadgets-gadget-title-bar';
-shindig.IfrGadget.prototype.cssClassTitle = 'gadgets-gadget-title';
-shindig.IfrGadget.prototype.cssClassTitleButtonBar =
+shindig.BaseIfrGadget.prototype.cssClassGadget = 'gadgets-gadget';
+shindig.BaseIfrGadget.prototype.cssClassTitleBar = 'gadgets-gadget-title-bar';
+shindig.BaseIfrGadget.prototype.cssClassTitle = 'gadgets-gadget-title';
+shindig.BaseIfrGadget.prototype.cssClassTitleButtonBar =
     'gadgets-gadget-title-button-bar';
-shindig.IfrGadget.prototype.cssClassGadgetUserPrefsDialog =
+shindig.BaseIfrGadget.prototype.cssClassGadgetUserPrefsDialog =
     'gadgets-gadget-user-prefs-dialog';
-shindig.IfrGadget.prototype.cssClassGadgetUserPrefsDialogActionBar =
+shindig.BaseIfrGadget.prototype.cssClassGadgetUserPrefsDialogActionBar =
     'gadgets-gadget-user-prefs-dialog-action-bar';
-shindig.IfrGadget.prototype.cssClassTitleButton = 'gadgets-gadget-title-button';
-shindig.IfrGadget.prototype.cssClassGadgetContent = 'gadgets-gadget-content';
-shindig.IfrGadget.prototype.rpcToken = (0x7FFFFFFF * Math.random()) | 0;
-shindig.IfrGadget.prototype.rpcRelay = '../container/rpc_relay.html';
+shindig.BaseIfrGadget.prototype.cssClassTitleButton = 'gadgets-gadget-title-button';
+shindig.BaseIfrGadget.prototype.cssClassGadgetContent = 'gadgets-gadget-content';
+shindig.BaseIfrGadget.prototype.rpcToken = (0x7FFFFFFF * Math.random()) | 0;
+shindig.BaseIfrGadget.prototype.rpcRelay = '../container/rpc_relay.html';
 
-shindig.IfrGadget.prototype.getTitleBarContent = function(continuation) {
+shindig.BaseIfrGadget.prototype.getTitleBarContent = function(continuation) {
   var settingsButton = this.hasViewablePrefs_() ?
       '<a href="#" onclick="shindig.container.getGadget(' + this.id +
           ').handleOpenUserPrefsDialog();return false;" class="' + this.cssClassTitleButton +
@@ -511,62 +520,36 @@ shindig.IfrGadget.prototype.getTitleBarC
       '">toggle</a></span></div>');
 };
 
-shindig.IfrGadget.prototype.getUserPrefsDialogContent = function(continuation) {
+shindig.BaseIfrGadget.prototype.getUserPrefsDialogContent = function(continuation) {
   continuation('<div id="' + this.getUserPrefsDialogId() + '" class="' +
       this.cssClassGadgetUserPrefsDialog + '"></div>');
 };
 
-shindig.IfrGadget.prototype.setServerBase = function(url) {
+shindig.BaseIfrGadget.prototype.setServerBase = function(url) {
   this.serverBase_ = url;
 };
 
-shindig.IfrGadget.prototype.getServerBase = function() {
+shindig.BaseIfrGadget.prototype.getServerBase = function() {
   return this.serverBase_;
 };
 
-shindig.IfrGadget.prototype.getMainContent = function(continuation) {
-  var iframeId = this.getIframeId();
-  gadgets.rpc.setRelayUrl(iframeId, this.serverBase_ + this.rpcRelay);
-  gadgets.rpc.setAuthToken(iframeId, this.rpcToken);
-  continuation('<div class="' + this.cssClassGadgetContent + '"><iframe id="' +
-      iframeId + '" name="' + iframeId + '" class="' + this.cssClassGadget +
-      '" src="about:blank' +
-      '" frameborder="no" scrolling="no"' +
-      (this.height ? ' height="' + this.height + '"' : '') +
-      (this.width ? ' width="' + this.width + '"' : '') +
-      '></iframe></div>');
+shindig.BaseIfrGadget.prototype.getMainContent = function(continuation) {
+  // proper sub-class has not been mixed-in yet
+  var gadget = this;
+  window.setTimeout( function() {
+    gadget.getMainContent(continuation);
+  }, 0);
 };
 
-shindig.IfrGadget.prototype.getIframeId = function() {
+shindig.BaseIfrGadget.prototype.getIframeId = function() {
   return this.GADGET_IFRAME_PREFIX_ + this.id;
 };
 
-shindig.IfrGadget.prototype.getUserPrefsDialogId = function() {
+shindig.BaseIfrGadget.prototype.getUserPrefsDialogId = function() {
   return this.getIframeId() + '_userPrefsDialog';
 };
 
-shindig.IfrGadget.prototype.getIframeUrl = function() {
-  return this.serverBase_ + 'ifr?' +
-      'container=' + this.CONTAINER +
-      '&mid=' +  this.id +
-      '&nocache=' + shindig.container.nocache_ +
-      '&country=' + shindig.container.country_ +
-      '&lang=' + shindig.container.language_ +
-      '&view=' + shindig.container.view_ +
-      (this.specVersion ? '&v=' + this.specVersion : '') +
-      (shindig.container.parentUrl_ ? '&parent=' + encodeURIComponent(shindig.container.parentUrl_) : '') +
-      (this.debug ? '&debug=1' : '') +
-      this.getAdditionalParams() +
-      this.getUserPrefsParams() +
-      (this.secureToken ? '&st=' + this.secureToken : '') +
-      '&url=' + encodeURIComponent(this.specUrl) +
-      '#rpctoken=' + this.rpcToken +
-      (this.viewParams ?
-          '&view-params=' +  encodeURIComponent(gadgets.json.stringify(this.viewParams)) : '') +
-      (this.hashData ? '&' + this.hashData : '');
-};
-
-shindig.IfrGadget.prototype.getUserPrefsParams = function() {
+shindig.BaseIfrGadget.prototype.getUserPrefsParams = function() {
   var params = '';
   for(var name in this.getUserPrefs()) {
     params += '&up_' + encodeURIComponent(name) + '=' +
@@ -575,7 +558,7 @@ shindig.IfrGadget.prototype.getUserPrefs
   return params;
 };
 
-shindig.IfrGadget.prototype.handleToggle = function() {
+shindig.BaseIfrGadget.prototype.handleToggle = function() {
   var gadgetIframe = document.getElementById(this.getIframeId());
   if (gadgetIframe) {
     var gadgetContent = gadgetIframe.parentNode;
@@ -585,7 +568,7 @@ shindig.IfrGadget.prototype.handleToggle
 };
 
 
-shindig.IfrGadget.prototype.hasViewablePrefs_ = function() {
+shindig.BaseIfrGadget.prototype.hasViewablePrefs_ = function() {
   for(var name in this.getUserPrefs()) {
     var pref = this.userPrefs[name];
     if (pref.type != 'hidden') {
@@ -596,7 +579,7 @@ shindig.IfrGadget.prototype.hasViewableP
 };
 
 
-shindig.IfrGadget.prototype.handleOpenUserPrefsDialog = function() {
+shindig.BaseIfrGadget.prototype.handleOpenUserPrefsDialog = function() {
   if (this.userPrefsDialogContentLoaded) {
     this.showUserPrefsDialog();
   } else {
@@ -615,7 +598,7 @@ shindig.IfrGadget.prototype.handleOpenUs
   }
 };
 
-shindig.IfrGadget.prototype.buildUserPrefsDialog = function(content) {
+shindig.BaseIfrGadget.prototype.buildUserPrefsDialog = function(content) {
   var userPrefsDialog = document.getElementById(this.getUserPrefsDialogId());
   userPrefsDialog.innerHTML = content +
       '<div class="' + this.cssClassGadgetUserPrefsDialogActionBar +
@@ -625,17 +608,17 @@ shindig.IfrGadget.prototype.buildUserPre
   userPrefsDialog.childNodes[0].style.display = '';
 };
 
-shindig.IfrGadget.prototype.showUserPrefsDialog = function(opt_show) {
+shindig.BaseIfrGadget.prototype.showUserPrefsDialog = function(opt_show) {
   var userPrefsDialog = document.getElementById(this.getUserPrefsDialogId());
   userPrefsDialog.style.display = (opt_show || opt_show === undefined)
       ? '' : 'none';
 };
 
-shindig.IfrGadget.prototype.hideUserPrefsDialog = function() {
+shindig.BaseIfrGadget.prototype.hideUserPrefsDialog = function() {
   this.showUserPrefsDialog(false);
 };
 
-shindig.IfrGadget.prototype.handleSaveUserPrefs = function() {
+shindig.BaseIfrGadget.prototype.handleSaveUserPrefs = function() {
   this.hideUserPrefsDialog();
 
   var numFields = document.getElementById('m_' + this.id +
@@ -652,15 +635,176 @@ shindig.IfrGadget.prototype.handleSaveUs
   this.refresh();
 };
 
-shindig.IfrGadget.prototype.handleCancelUserPrefs = function() {
+shindig.BaseIfrGadget.prototype.handleCancelUserPrefs = function() {
   this.hideUserPrefsDialog();
 };
 
-shindig.IfrGadget.prototype.refresh = function() {
+shindig.BaseIfrGadget.prototype.refresh = function() {
   var iframeId = this.getIframeId();
   document.getElementById(iframeId).src = this.getIframeUrl();
 };
 
+shindig.BaseIfrGadget.prototype.queryIfrGadgetType_ = function() {
+  // Get the gadget metadata and check if the gadget requires the 'pubsub-2'
+  // feature.  If so, then we use OpenAjax Hub in order to create and manage
+  // the iframe.  Otherwise, we create the iframe ourselves.
+  var request = {
+    context: {
+      country: "default",
+      language: "default",
+      view: "default",
+      container: "default"
+    },
+    gadgets: [{
+      url: this.specUrl,
+      moduleId: 1
+    }]
+  };
+
+  var makeRequestParams = {
+    "CONTENT_TYPE" : "JSON",
+    "METHOD" : "POST",
+    "POST_DATA" : gadgets.json.stringify(request)
+  };
+
+  var url = this.serverBase_+"metadata?st=" + this.secureToken;
+
+  gadgets.io.makeNonProxiedRequest(url,
+    handleJSONResponse,
+    makeRequestParams,
+    "application/javascript"
+  );
+  
+  var gadget = this;
+  function handleJSONResponse(obj) {
+    var requiresPubSub2 = false;
+    var arr = obj.data.gadgets[0].features;
+    for(var i = 0; i < arr.length; i++) {
+      if (arr[i] === "pubsub-2") {
+        requiresPubSub2 = true;
+        break;
+      }
+    }
+    var subClass = requiresPubSub2 ? shindig.OAAIfrGadget : shindig.IfrGadget;
+    for (var name in subClass) if (subClass.hasOwnProperty(name)) {
+      gadget[name] = subClass[name];
+    }
+  }
+};
+
+// ---------
+// IfrGadget
+
+shindig.IfrGadget = {
+  getMainContent: function(continuation) {
+    var iframeId = this.getIframeId();
+    gadgets.rpc.setRelayUrl(iframeId, this.serverBase_ + this.rpcRelay);
+    gadgets.rpc.setAuthToken(iframeId, this.rpcToken);
+    continuation('<div class="' + this.cssClassGadgetContent + '"><iframe id="' +
+        iframeId + '" name="' + iframeId + '" class="' + this.cssClassGadget +
+        '" src="about:blank' +
+        '" frameborder="no" scrolling="no"' +
+        (this.height ? ' height="' + this.height + '"' : '') +
+        (this.width ? ' width="' + this.width + '"' : '') +
+        '></iframe></div>');
+  },
+  
+  finishRender: function(chrome) {
+    window.frames[this.getIframeId()].location = this.getIframeUrl();
+  },
+  
+  getIframeUrl: function() {
+    return this.serverBase_ + 'ifr?' +
+        'container=' + this.CONTAINER +
+        '&mid=' +  this.id +
+        '&nocache=' + shindig.container.nocache_ +
+        '&country=' + shindig.container.country_ +
+        '&lang=' + shindig.container.language_ +
+        '&view=' + shindig.container.view_ +
+        (this.specVersion ? '&v=' + this.specVersion : '') +
+        (shindig.container.parentUrl_ ? '&parent=' + encodeURIComponent(shindig.container.parentUrl_) : '') +
+        (this.debug ? '&debug=1' : '') +
+        this.getAdditionalParams() +
+        this.getUserPrefsParams() +
+        (this.secureToken ? '&st=' + this.secureToken : '') +
+        '&url=' + encodeURIComponent(this.specUrl) +
+        '#rpctoken=' + this.rpcToken +
+        (this.viewParams ?
+            '&view-params=' +  encodeURIComponent(gadgets.json.stringify(this.viewParams)) : '') +
+        (this.hashData ? '&' + this.hashData : '');
+  }
+};
+
+
+// ---------
+// OAAIfrGadget
+
+shindig.OAAIfrGadget = {
+  getMainContent: function(continuation) {
+    continuation('<div id="' + this.cssClassGadgetContent + '-' + this.id +
+        '" class="' + this.cssClassGadgetContent + '"></div>');
+  },
+  
+  finishRender: function(chrome) {
+    var iframeAttrs = {
+      className: this.cssClassGadget,
+      frameborder: "no",
+      scrolling: "no"
+    };
+    if (this.height) {
+      iframeAttrs.height = this.height;
+    }
+    if (this.width) {
+      iframeAttrs.width = this.width;
+    }
+    
+    new OpenAjax.hub.IframeContainer(
+      gadgets.pubsub2router.hub,
+      this.getIframeId(),
+      {
+        Container: {
+          onSecurityAlert: function( source, alertType) {
+                gadgets.error("Security error for container " + source.getClientID() + " : " + alertType);
+                source.getIframe().src = "about:blank"; 
+// for debugging
+   //          },
+   //          onConnect: function( container ) {
+   //            gadgets.log("++ connected: " + container.getClientID());
+            }
+        },
+        IframeContainer: {
+          parent: document.getElementById(this.cssClassGadgetContent + '-' + this.id),
+          uri: this.getIframeUrl(),
+          tunnelURI: shindig.uri(this.serverBase_ + this.rpcRelay).resolve(shindig.uri(window.location.href)),
+          iframeAttrs: iframeAttrs
+        }
+      }
+    );
+  },
+  
+  getIframeUrl: function() {
+    return this.serverBase_ + 'ifr?' +
+        'container=' + this.CONTAINER +
+        '&mid=' +  this.id +
+        '&nocache=' + shindig.container.nocache_ +
+        '&country=' + shindig.container.country_ +
+        '&lang=' + shindig.container.language_ +
+        '&view=' + shindig.container.view_ +
+        (this.specVersion ? '&v=' + this.specVersion : '') +
+   //      (shindig.container.parentUrl_ ? '&parent=' + encodeURIComponent(shindig.container.parentUrl_) : '') +
+        (this.debug ? '&debug=1' : '') +
+        this.getAdditionalParams() +
+        this.getUserPrefsParams() +
+        (this.secureToken ? '&st=' + this.secureToken : '') +
+        '&url=' + encodeURIComponent(this.specUrl) +
+   //      '#rpctoken=' + this.rpcToken +
+        (this.viewParams ?
+            '&view-params=' +  encodeURIComponent(gadgets.json.stringify(this.viewParams)) : '') +
+   //      (this.hashData ? '&' + this.hashData : '');
+        (this.hashData ? '#' + this.hashData : '');
+  }
+};
+
 
 // ---------
 // Container
@@ -793,7 +937,7 @@ shindig.IfrContainer = function() {
 
 shindig.IfrContainer.inherits(shindig.Container);
 
-shindig.IfrContainer.prototype.gadgetClass = shindig.IfrGadget;
+shindig.IfrContainer.prototype.gadgetClass = shindig.BaseIfrGadget;
 
 shindig.IfrContainer.prototype.gadgetService = new shindig.IfrGadgetService();