Added: 
shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.3/iframe.js
URL: 
http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.3/iframe.js?rev=985116&view=auto
==============================================================================
--- 
shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.3/iframe.js
 (added)
+++ 
shindig/trunk/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.3/iframe.js
 Fri Aug 13 07:40:33 2010
@@ -0,0 +1,862 @@
+/*
+
+        Copyright 2006-2009 OpenAjax Alliance
+
+        Licensed 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.
+*/
+
+var OpenAjax = OpenAjax || {};
+OpenAjax.hub = OpenAjax.hub || {};
+OpenAjax.gadgets = typeof OpenAjax.gadgets === 'object' ? OpenAjax.gadgets :
+                   typeof gadgets === 'object' ? gadgets :
+                   {};
+OpenAjax.gadgets.rpctx = OpenAjax.gadgets.rpctx || {};
+
+(function() {
+    // 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) {
+        // "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) {
+            var scripts = document.getElementsByTagName("script");
+            // match "OpenAjax-mashup.js", "OpenAjaxManagedHub-all*.js", 
"OpenAjaxManagedHub-core*.js"
+            var reHub = /openajax(?:managedhub-(?:all|core).*|-mashup)\.js$/i;
+            for ( var i = scripts.length - 1; i >= 0; i-- ) {
+                var src = scripts[i].getAttribute( "src" );
+                if ( !src ) {
+                    continue;
+                }
+                
+                var m = src.match( reHub );
+                if ( m ) {
+                    var config = scripts[i].getAttribute( "oaaConfig" );
+                    if ( config ) {
+                        try {
+                            window.oaaConfig = eval( "({ " + config + " })" );
+                        } catch (e) {}
+                    }
+                    break;
+                }
+            }
+        }
+        
+        if (window.oaaConfig && window.oaaConfig.gadgetsGlobal) {
+            window.gadgets = OpenAjax.gadgets;
+        }
+    }
+})();
+
+
+if (!OpenAjax.hub.IframeContainer) {
+
+(function(){
+
+/**
+ * Create a new Iframe Container.
+ * @constructor
+ * @extends OpenAjax.hub.Container
+ * 
+ * IframeContainer implements the Container interface to provide a container
+ * that isolates client components into secure sandboxes by leveraging the
+ * isolation features provided by browser iframes.
+ * 
+ * SECURITY
+ * 
+ * In order for the connection between the IframeContainer and IframeHubClient
+ * to be fully secure, you must specify a valid 'tunnelURI'. Note that if you
+ * do specify a 'tunnelURI', then only the WPM and NIX transports are used,
+ * covering the following browsers:
+ *   IE 6+, Firefox 3+, Safari 4+, Chrome 2+, Opera 9+.
+ * 
+ * If no 'tunnelURI' is specified, then some security features are disabled:
+ * the IframeContainer will not report FramePhish errors, and on some browsers
+ * IframeContainer and IframeHubClient will not be able to validate the
+ * identity of their partner (i.e. getPartnerOrigin() will return 'null').
+ * However, not providing 'tunnelURI' allows the additional use of the RMR
+ * and FE transports -- in addition to the above browsers, the Hub code will
+ * also work on:
+ *   Firefox 1 & 2, Safari 2 & 3, Chrome 1.
+ * 
+ * @param {OpenAjax.hub.ManagedHub} hub
+ *    Managed Hub instance to which this Container belongs
+ * @param {String} clientID
+ *    A string ID that identifies a particular client of a Managed Hub. Unique
+ *    within the context of the ManagedHub.
+ * @param {Object} params  
+ *    Parameters used to instantiate the IframeContainer.
+ *    Once the constructor is called, the params object belongs exclusively to
+ *    the IframeContainer. The caller MUST not modify it.
+ *    The following are the pre-defined properties on params:
+ * @param {Function} params.Container.onSecurityAlert
+ *    Called when an attempted security breach is thwarted.  Function is 
defined
+ *    as follows:  function(container, securityAlert)
+ * @param {Function} [params.Container.onConnect]
+ *    Called when the client connects to the Managed Hub.  Function is defined
+ *    as follows:  function(container)
+ * @param {Function} [params.Container.onDisconnect]
+ *    Called when the client disconnects from the Managed Hub.  Function is
+ *    defined as follows:  function(container)
+ * @param {Object} [params.Container.scope]
+ *    Whenever one of the Container's callback functions is called, references
+ *    to "this" in the callback will refer to the scope object. If no scope is
+ *    provided, default is window.
+ * @param {Function} [params.Container.log]
+ *    Optional logger function. Would be used to log to console.log or
+ *    equivalent. 
+ * @param {Object} params.IframeContainer.parent
+ *    DOM element that is to be parent of iframe
+ * @param {String} params.IframeContainer.uri
+ *    Initial Iframe URI (Container will add parameters to this URI)
+ * @param {String} [params.IframeContainer.tunnelURI]
+ *    URI of the tunnel iframe. Must be from the same origin as the page which
+ *    instantiates the IframeContainer. If not specified, connection will not
+ *    be fully secure (see SECURITY section).
+ * @param {Object} [params.IframeContainer.iframeAttrs]
+ *    Attributes to add to IFRAME DOM entity.  For example:
+ *              { style: { width: "100%",
+ *                         height: "100%" },
+ *                className: "some_class" }
+ * @param {Number} [params.IframeContainer.timeout]
+ *    Load timeout in milliseconds.  If not specified, defaults to 15000.  If
+ *    the client at params.IframeContainer.uri does not establish a connection
+ *    with this container in the given time, the onSecurityAlert callback is
+ *    called with a LoadTimeout error code.
+ * @param {Function} [params.IframeContainer.seed]
+ *    A function that returns a string that will be used to seed the
+ *    pseudo-random number generator, which is used to create the security
+ *    tokens.  An implementation of IframeContainer may choose to ignore this
+ *    value.
+ * @param {Number} [params.IframeContainer.tokenLength]
+ *    Length of the security tokens used when transmitting messages.  If not
+ *    specified, defaults to 6.  An implementation of IframeContainer may 
choose
+ *    to ignore this value.
+ *
+ * @throws {OpenAjax.hub.Error.BadParameters}   if required params are not
+ *          present or null
+ * @throws {OpenAjax.hub.Error.Duplicate}   if a Container with this clientID
+ *          already exists in the given Managed Hub
+ * @throws {OpenAjax.hub.Error.Disconnected}   if hub is not connected
+ */
+OpenAjax.hub.IframeContainer = function( hub, clientID, params )
+{
+    assertValidParams( arguments );
+    
+    var container = this;
+    var scope = params.Container.scope || window;
+    var connected = false;
+    var subs = {};
+    var securityToken;
+    var internalID;
+    var timeout = params.IframeContainer.timeout || 15000;
+    var loadTimer;
+
+    if ( params.Container.log ) {
+        var log = function( msg ) {
+            try {
+                params.Container.log.call( scope, "IframeContainer::" + 
clientID + ": " + msg );
+            } catch( e ) {
+                OpenAjax.hub._debugger();
+            }
+        };
+    } else {
+        log = function() {};
+    }
+    
+    
+    this._init = function() {
+        // add to ManagedHub first, to see if clientID is a duplicate
+        hub.addContainer( this );
+        
+        // Create an "internal" ID, which is guaranteed to be unique within the
+        // window, not just within the hub.
+        internalID = OpenAjax.hub.IframeContainer._rpcRouter.add( clientID, 
this );
+        securityToken = generateSecurityToken( params, scope, log );
+        
+        var relay = null;
+        var transportName = OpenAjax.gadgets.rpc.getRelayChannel();
+        if ( params.IframeContainer.tunnelURI ) {
+            if ( transportName !== "wpm" && transportName !== "nix" ) {
+                throw new Error( OpenAjax.hub.Error.IncompatBrowser );
+            }
+        } else {
+            log( "WARNING: Parameter 'IframeContaienr.tunnelURI' not 
specified. Connection will not be fully secure." );
+            if ( transportName === "rmr" ) {
+                relay = OpenAjax.gadgets.rpc.getOrigin( 
params.IframeContainer.uri ) + "/robots.txt"; 
+            }
+        }
+        
+        // Create IFRAME to hold the client
+        createIframe();
+        
+        OpenAjax.gadgets.rpc.setupReceiver( internalID, relay );
+        
+        startLoadTimer();
+    };
+
+        
+  /*** OpenAjax.hub.Container interface ***/
+   
+    this.sendToClient = function( topic, data, subscriptionID ) {
+        OpenAjax.gadgets.rpc.call( internalID, "openajax.pubsub", null, "pub", 
topic, data,
+                                   subscriptionID );
+    };
+
+    this.remove = function() {
+        finishDisconnect();
+        clearTimeout( loadTimer );
+        OpenAjax.gadgets.rpc.removeReceiver( internalID );
+        var iframe = document.getElementById( internalID );
+        iframe.parentNode.removeChild( iframe );
+        OpenAjax.hub.IframeContainer._rpcRouter.remove( internalID );
+    };
+
+    this.isConnected = function() {
+        return connected;
+    };
+    
+    this.getClientID = function() {
+        return clientID;
+    };
+
+    this.getPartnerOrigin = function() {
+        if ( connected ) {
+            var origin = OpenAjax.gadgets.rpc.getReceiverOrigin( internalID );
+            if ( origin ) {
+                // remove port if present
+                return ( /^([a-zA-Z]+:\/\/[^:]+).*/.exec( origin )[1] );
+            }
+        }
+        return null;
+    };
+    
+    this.getParameters = function() {
+        return params;
+    };
+    
+    this.getHub = function() {
+        return hub;
+    };
+    
+    
+  /*** OpenAjax.hub.IframeContainer interface ***/
+    
+    /**
+     * Get the iframe associated with this iframe container
+     * 
+     * This function returns the iframe associated with an IframeContainer,
+     * allowing the Manager Application to change its size, styles, 
scrollbars, etc.
+     * 
+     * CAUTION: The iframe is owned exclusively by the IframeContainer. The 
Manager
+     * Application MUST NOT destroy the iframe directly. Also, if the iframe is
+     * hidden and disconnected, the Manager Application SHOULD NOT attempt to 
make
+     * it visible. The Container SHOULD automatically hide the iframe when it 
is
+     * disconnected; to make it visible would introduce security risks. 
+     * 
+     * @returns iframeElement
+     * @type {Object}
+     */
+    this.getIframe = function() {
+        return document.getElementById( internalID );
+    };
+    
+    
+  /*** private functions ***/
+
+    function assertValidParams( args ) {
+        var hub = args[0],
+            clientID = args[1],
+            params = args[2];
+        if ( ! hub || ! clientID || ! params || ! params.Container ||
+             ! params.Container.onSecurityAlert || ! params.IframeContainer ||
+             ! params.IframeContainer.parent || ! params.IframeContainer.uri ) 
{
+            throw new Error( OpenAjax.hub.Error.BadParameters );
+        }
+    }
+    
+    this._handleIncomingRPC = function( command, topic, data ) {
+        switch ( command ) {
+            // publish
+            // 'data' is topic message
+            case "pub":
+                hub.publishForClient( container, topic, data );
+                break;
+            
+            // subscribe
+            // 'data' is subscription ID
+            case "sub":
+                var errCode = "";  // empty string is success
+                try {
+                    subs[ data ] = hub.subscribeForClient( container, topic, 
data );
+                } catch( e ) {
+                    errCode = e.message;
+                }
+                return errCode;
+            
+            // unsubscribe
+            // 'data' is subscription ID
+            case "uns":
+                var handle = subs[ data ];
+                hub.unsubscribeForClient( container, handle );
+                delete subs[ data ];
+                return data;
+            
+            // connect
+            case "con":
+                finishConnect();
+                return true;
+            
+            // disconnect
+            case "dis":
+                startLoadTimer();
+                finishDisconnect();
+                if ( params.Container.onDisconnect ) {
+                    try {
+                        params.Container.onDisconnect.call( scope, container );
+                    } catch( e ) {
+                        OpenAjax.hub._debugger();
+                        log( "caught error from onDisconnect callback to 
constructor: " + e.message );
+                    }
+                }
+                return true;
+        }
+    };
+    
+    this._onSecurityAlert = function( error ) {
+        invokeSecurityAlert( rpcErrorsToOAA[ error ] );
+    };
+    
+    // The RPC code requires that the 'name' attribute be properly set on the
+    // iframe.  However, setting the 'name' property on the iframe object
+    // returned from 'createElement("iframe")' doesn't work on IE --
+    // 'window.name' returns null for the code within the iframe.  The
+    // workaround is to set the 'innerHTML' of a span to the iframe's HTML 
code,
+    // with 'name' and other attributes properly set.
+    function createIframe() {
+        var span = document.createElement( "span" );
+        params.IframeContainer.parent.appendChild( span );
+        
+        var iframeText = '<iframe id="' + internalID + '" name="' + internalID 
+
+                '" src="javascript:\'<html></html>\'"';
+        
+        // Add iframe attributes
+        var styleText = '';
+        var attrs = params.IframeContainer.iframeAttrs;
+        if ( attrs ) {
+            for ( var attr in attrs ) {
+                switch ( attr ) {
+                    case "style":
+                        for ( var style in attrs.style ) {
+                            styleText += style + ':' + attrs.style[ style ] + 
';';
+                        }
+                        break;
+                    case "className":
+                        iframeText += ' class="' + attrs[ attr ] + '"';
+                        break;
+                    default:
+                        iframeText += ' ' + attr + '="' + attrs[ attr ] + '"';
+                }
+            }
+        }
+        
+        // initially hide IFRAME content, in order to lessen frame phishing 
impact
+        styleText += 'visibility:hidden;';
+        iframeText += ' style="' + styleText + '"></iframe>';
+        
+        span.innerHTML = iframeText;
+        
+        var tunnel = params.IframeContainer.tunnelURI;
+        document.getElementById( internalID ).src = params.IframeContainer.uri 
+
+                "#rpctoken=" + securityToken +
+                (tunnel ? "&parent=" + encodeURIComponent( tunnel ) + 
"&forcesecure=true" :
+                          "&oaaParent=" + encodeURIComponent( 
OpenAjax.gadgets.rpc.getOrigin( window.location.href )));
+    }
+    
+    // If the relay iframe used by RPC has not been loaded yet, then we won't 
have unload protection
+    // at this point.  Since we can't detect when the relay iframe has loaded, 
we use a two stage
+    // connection process.  First, the child sends a connection msg and the 
container sends an ack.
+    // Then the container sends a connection msg and the child replies with an 
ack.  Since the
+    // container can only send a message if the relay iframe has loaded, then 
we know if we get an
+    // ack here that the relay iframe is ready.  And we are fully connected.
+    function finishConnect() {
+        // connect acknowledgement
+        function callback( result ) {
+            if ( result ) {
+                connected = true;
+                clearTimeout( loadTimer );
+                document.getElementById( internalID ).style.visibility = 
"visible";
+                if ( params.Container.onConnect ) {
+                    try {
+                        params.Container.onConnect.call( scope, container );
+                    } catch( e ) {
+                        OpenAjax.hub._debugger();
+                        log( "caught error from onConnect callback to 
constructor: " + e.message );
+                    }
+                }
+            }
+        }
+        OpenAjax.gadgets.rpc.call( internalID, "openajax.pubsub", callback, 
"cmd", "con" );
+    }
+    
+    function finishDisconnect() {
+        if ( connected ) {
+            connected = false;
+            document.getElementById( internalID ).style.visibility = "hidden";
+        
+            // unsubscribe from all subs
+            for ( var s in subs ) {
+                hub.unsubscribeForClient( container, subs[s] );
+            }
+            subs = {};
+        }
+    }
+    
+    function invokeSecurityAlert( errorMsg ) {
+        try {
+            params.Container.onSecurityAlert.call( scope, container, errorMsg 
);
+        } catch( e ) {
+            OpenAjax.hub._debugger();
+            log( "caught error from onSecurityAlert callback to constructor: " 
+ e.message );
+        }
+    }
+    
+    function startLoadTimer() {
+        loadTimer = setTimeout(
+            function() {
+                // alert the security alert callback
+                invokeSecurityAlert( OpenAjax.hub.SecurityAlert.LoadTimeout );
+                // don't receive any more messages from HubClient
+                container._handleIncomingRPC = function() {};
+            },
+            timeout
+        );
+    }
+    
+    
+    this._init();
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Create a new IframeHubClient.
+ * @constructor
+ * @extends OpenAjax.hub.HubClient
+ * 
+ * @param {Object} params
+ *    Once the constructor is called, the params object belongs to the
+ *    HubClient. The caller MUST not modify it.
+ *    The following are the pre-defined properties on params:
+ * @param {Function} params.HubClient.onSecurityAlert
+ *     Called when an attempted security breach is thwarted
+ * @param {Object} [params.HubClient.scope]
+ *     Whenever one of the HubClient's callback functions is called,
+ *     references to "this" in the callback will refer to the scope object.
+ *     If not provided, the default is window.
+ * @param {Function} [params.HubClient.log]
+ *     Optional logger function. Would be used to log to console.log or
+ *     equivalent. 
+ * @param {Boolean} [params.IframeHubClient.requireParentVerifiable]
+ *     Set to true in order to require that this IframeHubClient use a
+ *     transport that can verify the parent Container's identity.
+ * @param {Function} [params.IframeHubClient.seed]
+ *     A function that returns a string that will be used to seed the
+ *     pseudo-random number generator, which is used to create the security
+ *     tokens.  An implementation of IframeHubClient may choose to ignore
+ *     this value.
+ * @param {Number} [params.IframeHubClient.tokenLength]
+ *     Length of the security tokens used when transmitting messages.  If
+ *     not specified, defaults to 6.  An implementation of IframeHubClient
+ *     may choose to ignore this value.
+ *     
+ * @throws {OpenAjax.hub.Error.BadParameters} if any of the required
+ *          parameters is missing, or if a parameter value is invalid in 
+ *          some way.
+ */
+OpenAjax.hub.IframeHubClient = function( params )
+{
+    if ( ! params || ! params.HubClient || ! params.HubClient.onSecurityAlert 
) {
+        throw new Error( OpenAjax.hub.Error.BadParameters );
+    }
+    
+    var client = this;
+    var scope = params.HubClient.scope || window;
+    var connected = false;
+    var subs = {};
+    var subIndex = 0;
+    var clientID;
+//    var securityToken;    // XXX still need "securityToken"?
+    
+    if ( params.HubClient.log ) {
+        var log = function( msg ) {
+            try {
+                params.HubClient.log.call( scope, "IframeHubClient::" + 
clientID + ": " + msg );
+            } catch( e ) {
+                OpenAjax.hub._debugger();
+            }
+        };
+    } else {
+        log = function() {};
+    }
+    
+    this._init = function() {
+        var urlParams = OpenAjax.gadgets.util.getUrlParameters();
+        if ( ! urlParams.parent ) {
+            // The RMR transport does not require a valid relay file, but does 
need a URL
+            // in the parent's domain. The URL does not need to point to valid 
file, so just
+            // point to 'robots.txt' file. See RMR transport code for more 
info.
+            var parent = urlParams.oaaParent + "/robots.txt";
+            OpenAjax.gadgets.rpc.setupReceiver( "..", parent );
+        }
+        
+        if ( params.IframeHubClient && 
params.IframeHubClient.requireParentVerifiable &&
+             OpenAjax.gadgets.rpc.getReceiverOrigin( ".." ) === null ) {
+            // If user set 'requireParentVerifiable' to true but RPC transport 
does not
+            // support this, throw error.
+            OpenAjax.gadgets.rpc.removeReceiver( ".." );
+            throw new Error( OpenAjax.hub.Error.IncompatBrowser );
+        }
+        
+        OpenAjax.hub.IframeContainer._rpcRouter.add( "..", this );
+//        securityToken = generateSecurityToken( params, scope, log );    // 
XXX still necessary?
+
+        var internalID = OpenAjax.gadgets.rpc.RPC_ID;
+        if ( ! internalID ) {
+            throw new Error( OpenAjax.hub.Error.WrongProtocol );
+        }
+        clientID = decodeURIComponent( internalID.substr( 
internalID.indexOf("_") + 1 ) );
+    };
+    
+  /*** HubClient interface ***/
+
+    this.connect = function( onComplete, scope ) {
+        if ( connected ) {
+            throw new Error( OpenAjax.hub.Error.Duplicate );
+        }
+        
+        // connect acknowledgement
+        function callback( result ) {
+            if ( result ) {
+                connected = true;
+                if ( onComplete ) {
+                    try {
+                        onComplete.call( scope || window, client, true );
+                    } catch( e ) {
+                        OpenAjax.hub._debugger();
+                        log( "caught error from onComplete callback to 
connect(): " + e.message );
+                    }
+                }
+            }
+        }
+        OpenAjax.gadgets.rpc.call( "..", "openajax.pubsub", callback, "con" );
+    };
+    
+    this.disconnect = function( onComplete, scope ) {
+        if ( !connected ) {
+            throw new Error( OpenAjax.hub.Error.Disconnected );
+        }
+        
+        connected = false;
+        
+        // disconnect acknowledgement
+        var callback = null;
+        if ( onComplete ) {
+            callback = function( result ) {
+                try {
+                    onComplete.call( scope || window, client, true );
+                } catch( e ) {
+                    OpenAjax.hub._debugger();
+                    log( "caught error from onComplete callback to 
disconnect(): " + e.message );
+                }
+            };
+        }
+        OpenAjax.gadgets.rpc.call( "..", "openajax.pubsub", callback, "dis" );
+    };
+    
+    this.getPartnerOrigin = function() {
+        if ( connected ) {
+            var origin = OpenAjax.gadgets.rpc.getReceiverOrigin( ".." );
+            if ( origin ) {
+                // remove port if present
+                return ( /^([a-zA-Z]+:\/\/[^:]+).*/.exec( origin )[1] );
+            }
+        }
+        return null;
+    };
+    
+    this.getClientID = function() {
+        return clientID;
+    };
+    
+  /*** Hub interface ***/
+    
+    this.subscribe = function( topic, onData, scope, onComplete, 
subscriberData ) {
+        assertConn();
+        assertSubTopic( topic );
+        if ( ! onData ) {
+            throw new Error( OpenAjax.hub.Error.BadParameters );
+        }
+    
+        scope = scope || window;
+        var subID = "" + subIndex++;
+        subs[ subID ] = { cb: onData, sc: scope, d: subscriberData };
+        
+        // subscribe acknowledgement
+        function callback( result ) {
+            if ( result !== '' ) {    // error
+                delete subs[ subID ];
+            }
+            if ( onComplete ) {
+                try {
+                    onComplete.call( scope, subID, result === "", result );
+                } catch( e ) {
+                    OpenAjax.hub._debugger();
+                    log( "caught error from onComplete callback to 
subscribe(): " + e.message );
+                }
+            }
+        }
+        OpenAjax.gadgets.rpc.call( "..", "openajax.pubsub", callback, "sub", 
topic, subID );
+        
+        return subID;
+    };
+    
+    this.publish = function( topic, data ) {
+        assertConn();
+        assertPubTopic( topic );
+        OpenAjax.gadgets.rpc.call( "..", "openajax.pubsub", null, "pub", 
topic, data );
+    };
+    
+    this.unsubscribe = function( subscriptionID, onComplete, scope ) {
+        assertConn();
+        if ( ! subscriptionID ) {
+            throw new Error( OpenAjax.hub.Error.BadParameters );
+        }
+        
+        // if no such subscriptionID, or in process of unsubscribing given ID, 
throw error
+        if ( ! subs[ subscriptionID ] || subs[ subscriptionID ].uns ) {
+            throw new Error( OpenAjax.hub.Error.NoSubscription );
+        }
+        
+        // unsubscribe in progress
+        subs[ subscriptionID ].uns = true;
+        
+        // unsubscribe acknowledgement
+        function callback( result ) {
+            delete subs[ subscriptionID ];
+            if ( onComplete ) {
+                try {
+                    onComplete.call( scope || window, subscriptionID, true );
+                } catch( e ) {
+                    OpenAjax.hub._debugger();
+                    log( "caught error from onComplete callback to 
unsubscribe(): " + e.message );
+                }
+            }
+        }
+        OpenAjax.gadgets.rpc.call( "..", "openajax.pubsub", callback, "uns", 
null, subscriptionID );
+    };
+    
+    this.isConnected = function() {
+        return connected;
+    };
+    
+    this.getScope = function() {
+        return scope;
+    };
+    
+    this.getSubscriberData = function( subscriptionID ) {
+        assertConn();
+        if ( subs[ subscriptionID ] ) {
+            return subs[ subscriptionID ].d;
+        }
+        throw new Error( OpenAjax.hub.Error.NoSubscription );
+    };
+    
+    this.getSubscriberScope = function( subscriptionID ) {
+        assertConn();
+        if ( subs[ subscriptionID ] ) {
+            return subs[ subscriptionID ].sc;
+        }
+        throw new Error( OpenAjax.hub.Error.NoSubscription );
+    };
+    
+    this.getParameters = function() {
+        return params;
+    };
+    
+  /*** private functions ***/
+    
+    this._handleIncomingRPC = function( command, topic, data, subscriptionID ) 
{
+        if ( command === "pub" ) {
+            // if subscription exists and we are not in process of 
unsubscribing...
+            if ( subs[ subscriptionID ] && ! subs[ subscriptionID ].uns ) {
+                try {
+                    subs[ subscriptionID ].cb.call( subs[ subscriptionID ].sc, 
topic,
+                            data, subs[ subscriptionID ].d );
+                } catch( e ) {
+                    OpenAjax.hub._debugger();
+                    log( "caught error from onData callback to subscribe(): " 
+ e.message );
+                }
+            }
+        }
+        // else if command === "cmd"...
+        
+        // First time this function is called, topic should be "con".  This is 
the 2nd stage of the
+        // connection process.  Simply need to return "true" in order to send 
an acknowledgement
+        // back to container.  See finishConnect() in the container object.
+        if ( topic === "con" ) {
+          return true;
+        }
+        return false;
+    };
+    
+    function assertConn() {
+        if ( ! connected ) {
+            throw new Error( OpenAjax.hub.Error.Disconnected );
+        }
+    }
+    
+    function assertSubTopic( topic )
+    {
+        if ( ! topic ) {
+            throw new Error( OpenAjax.hub.Error.BadParameters );
+        }
+        var path = topic.split(".");
+        var len = path.length;
+        for (var i = 0; i < len; i++) {
+            var p = path[i];
+            if ((p === "") ||
+               ((p.indexOf("*") != -1) && (p != "*") && (p != "**"))) {
+                throw new Error( OpenAjax.hub.Error.BadParameters );
+            }
+            if ((p == "**") && (i < len - 1)) {
+                throw new Error( OpenAjax.hub.Error.BadParameters );
+            }
+        }
+    }
+    
+    function assertPubTopic( topic ) {
+        if ( !topic || topic === "" || (topic.indexOf("*") != -1) ||
+            (topic.indexOf("..") != -1) ||  (topic.charAt(0) == ".") ||
+            (topic.charAt(topic.length-1) == "."))
+        {
+            throw new Error( OpenAjax.hub.Error.BadParameters );
+        }
+    }
+    
+//    function invokeSecurityAlert( errorMsg ) {
+//        try {
+//            params.HubClient.onSecurityAlert.call( scope, client, errorMsg );
+//        } catch( e ) {
+//            OpenAjax.hub._debugger();
+//            log( "caught error from onSecurityAlert callback to constructor: 
" + e.message );
+//        }
+//    }
+
+    
+    this._init();
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+    // RPC object contents:
+    //   s: Service Name
+    //   f: From
+    //   c: The callback ID or 0 if none.
+    //   a: The arguments for this RPC call.
+    //   t: The authentication token.
+OpenAjax.hub.IframeContainer._rpcRouter = function() {
+    var receivers = {};
+    
+    function router() {
+        var r = receivers[ this.f ];
+        if ( r ) {
+            return r._handleIncomingRPC.apply( r, arguments );
+        }
+    }
+    
+    function onSecurityAlert( receiverId, error ) {
+        var r = receivers[ receiverId ];
+        if ( r ) {
+          r._onSecurityAlert.call( r, error );
+        }
+    }
+    
+    return {
+        add: function( id, receiver ) {
+            function _add( id, receiver ) {
+                if ( id === ".." ) {
+                    if ( ! receivers[ ".." ] ) {
+                        receivers[ ".." ] = receiver;
+                    }
+                    return;
+                }
+                
+                id = encodeURIComponent( id );
+                do {
+                    // a client with the specified ID already exists on this 
page;
+                    // create a unique ID
+                    newID = ((0x7fff * Math.random()) | 0).toString(16) + "_" 
+ id;
+                } while ( receivers[ newID ] );
+                receivers[ newID ] = receiver;
+                return newID;
+            }
+            
+            // when this function is first called, register the RPC service
+            OpenAjax.gadgets.rpc.register( "openajax.pubsub", router );
+            OpenAjax.gadgets.rpc.config({
+                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;
+            
+            this.add = _add;
+            return _add( id, receiver );
+        },
+        
+        remove: function( id ) {
+            delete receivers[ id ];
+        }
+    };
+}();
+
+var rpcErrorsToOAA = {};
+
+////////////////////////////////////////////////////////////////////////////////
+
+function generateSecurityToken( params, scope, log, overrideTokenLength ) {
+    if ( ! OpenAjax.hub.IframeContainer._prng ) {
+        // create pseudo-random number generator with a default seed
+        var seed = new Date().getTime() + Math.random() + document.cookie;
+        OpenAjax.hub.IframeContainer._prng = OpenAjax._smash.crypto.newPRNG( 
seed );
+    }
+    
+    var p = params.IframeContainer || params.IframeHubClient;
+    if ( p && p.seed ) {
+        try {
+            var extraSeed = p.seed.call( scope );
+            OpenAjax.hub.IframeContainer._prng.addSeed( extraSeed );
+        } catch( e ) {
+            OpenAjax.hub._debugger();
+            log( "caught error from 'seed' callback: " + e.message );
+        }
+    }
+    
+    var tokenLength = overrideTokenLength || (p && p.tokenLength) || 6;
+    return OpenAjax.hub.IframeContainer._prng.nextRandomB64Str( tokenLength );
+}
+
+})();
+}
\ No newline at end of file

Added: 
shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/feature.xml
URL: 
http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/feature.xml?rev=985116&view=auto
==============================================================================
--- 
shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/feature.xml 
(added)
+++ 
shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/feature.xml 
Fri Aug 13 07:40:33 2010
@@ -0,0 +1,30 @@
+<?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>
+  <name>pubsub-2</name>
+  <dependency>globals</dependency>
+  <dependency>org.openajax.hub-2.0.3</dependency>
+  <gadget>
+    <script src="pubsub-2.js"/>
+    <script src="taming.js"/>
+  </gadget>
+  <container>
+    <script src="pubsub-2-router.js"/>
+  </container>
+</feature>

Added: 
shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/pubsub-2-router.js
URL: 
http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/pubsub-2-router.js?rev=985116&view=auto
==============================================================================
--- 
shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/pubsub-2-router.js
 (added)
+++ 
shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/pubsub-2-router.js
 Fri Aug 13 07:40:33 2010
@@ -0,0 +1,72 @@
+/*
+ * 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 Container-side message router for PubSub, a gadget-to-gadget
+ * communication library.
+ * 
+ * Uses OpenAjax Hub's ManagedHub class to route pubsub messages and to provide
+ * manager callbacks that allow control over these messages.
+ */
+
+/**
+ * @static
+ * @class Routes PubSub messages.
+ * @name gadgets.pubsub2router
+ */
+gadgets.pubsub2router = function() {
+  return /** @scope gadgets.pubsub2router */ {
+    /**
+     * Initialize the pubsub message router.
+     * 
+     * 'opt_params' is passed directly to the ManagedHub constructor.
+     * For example:
+     * 
+     *     gadgets.pubsub2router.init({
+     *         onSubscribe: function(topic, container) {
+     *           ...
+     *           return true; // return false to reject the request.
+     *         },
+     *         onPublish: function(topic, data, pcont, scont) {
+     *           ...
+     *           return true; // return false to reject the request.
+     *         },
+     *         onUnsubscribe: function(topic, container) {
+     *           ...
+     *         }
+     *     });
+     * 
+     * Alternatively, if you have already created a ManagedHub instance and 
wish
+     * to use that, you can specify it in 'opt_params.hub'.
+     * 
+     * @param {Object} opt_params
+     * @see 
http://openajax.org/member/wiki/OpenAjax_Hub_2.0_Specification_Managed_Hub_APIs#OpenAjax.hub.ManagedHub_constructor
+     */
+    init: function( opt_params ) {
+      if (opt_params.hub) {
+        this.hub = opt_params.hub;
+      } else {
+        this.hub = new OpenAjax.hub.ManagedHub({
+          onPublish: opt_params.onPublish,
+          onSubscribe: opt_params.onSubscribe,
+          onUnsubscribe: opt_params.onUnsubscribe
+        });
+      }
+    }
+  };
+}();

Added: 
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=985116&view=auto
==============================================================================
--- 
shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/pubsub-2.js 
(added)
+++ 
shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/pubsub-2.js 
Fri Aug 13 07:40:33 2010
@@ -0,0 +1,92 @@
+/*
+ * 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 Gadget-side PubSub library for gadget-to-gadget communication.
+ * 
+ * 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);
+ * 
+ * The <gadget instance>.PubSub 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:
+ * 
+ *     <gadget instance>.PubSubSettings = {
+ *         // 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
+ *         params: {},
+ *         // Callback that is invoked when connection to parent is 
established,
+ *         // or when errors occur.
+ *         // @see 
http://openajax.org/member/wiki/OpenAjax_Hub_2.0_Specification_Managed_Hub_APIs#OpenAjax.hub.HubClient.prototype.connect
+ *         onConnect: <function>
+ *     }
+ * 
+ * For example, to set a security alert callback:
+ * 
+ *     <gadget instance>.PubSubSettings.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 = {
+        // Set default HubClient constructor params object
+        params: {
+            HubClient: {
+                onSecurityAlert: function(alertSource, alertType) {
+                    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;
+    }
+    
+    // Register an onLoad handler
+    gadgets.util.registerOnLoadHandler(function() {
+        try {
+            // Create the HubClient.
+            gadgetInstance.PubSub = new 
OpenAjax.hub.IframeHubClient(gadgetInstance.PubSubSettings.params);
+            
+            // Connect to the ManagedHub
+            
gadgetInstance.PubSub.connect(gadgetInstance.PubSubSettings.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 + "]");
+        }
+    });
+})();

Copied: 
shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/taming.js 
(from r985115, shindig/trunk/content/container/rpc_relay.html)
URL: 
http://svn.apache.org/viewvc/shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/taming.js?p2=shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/taming.js&p1=shindig/trunk/content/container/rpc_relay.html&r1=985115&r2=985116&rev=985116&view=diff
==============================================================================
--- shindig/trunk/content/container/rpc_relay.html (original)
+++ shindig/trunk/extras/src/main/javascript/features-extras/pubsub-2/taming.js 
Fri Aug 13 07:40:33 2010
@@ -1,4 +1,4 @@
-<!--
+/*
  * 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
@@ -7,7 +7,7 @@
  * "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
+ *     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
@@ -15,13 +15,18 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
--->
-<script>
-var u = location.href, h = u.substr(u.indexOf('#') + 1).split('&'), t, r;
-try {
-  t = h[0] === '..' ? parent.parent : parent.frames[h[0]];
-  r = t.gadgets.rpc.receive;
-} catch (e) {
-}
-r && r(h);
-</script>
+ */
+
+/**
+ * @class
+ * Tame and expose core gadgets.pubsub.* API to cajoled gadgets
+ */
+// XXX not sure what to do here
+//var tamings___ = tamings___ || [];
+//tamings___.push(function(imports) {
+//  caja___.whitelistFuncs([
+//    [gadgets.pubsub, 'publish'],
+//    [gadgets.pubsub, 'subscribe'],
+//    [gadgets.pubsub, 'unsubscribe']
+//  ]);
+//});

Modified: 
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsonRpcHandler.java
URL: 
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsonRpcHandler.java?rev=985116&r1=985115&r2=985116&view=diff
==============================================================================
--- 
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsonRpcHandler.java
 (original)
+++ 
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/JsonRpcHandler.java
 Fri Aug 13 07:40:33 2010
@@ -26,9 +26,11 @@ import org.apache.shindig.gadgets.spec.L
 import org.apache.shindig.gadgets.spec.ModulePrefs;
 import org.apache.shindig.gadgets.spec.UserPref;
 import org.apache.shindig.gadgets.spec.View;
+import org.apache.shindig.gadgets.spec.Feature;
 import org.apache.shindig.gadgets.uri.IframeUriManager;
 
 import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
 import com.google.inject.Inject;
 
 import org.json.JSONArray;
@@ -172,7 +174,23 @@ public class JsonRpcHandler {
         // Features.
         Set<String> feats = prefs.getFeatures().keySet();
         String[] features = feats.toArray(new String[feats.size()]);
-
+        
+        // Feature details
+        // The following renders an object containing feature details, of the 
form 
+        //   { <featureName>*: { "required": <boolean>, "parameters": { 
<paramName>*: <string> } } }
+        JSONObject featureDetailList = new JSONObject();
+        for (Feature featureSpec : prefs.getFeatures().values()) {
+          JSONObject featureDetail = new JSONObject();
+          featureDetail.put("required", featureSpec.getRequired());
+          JSONObject featureParameters = new JSONObject();
+          featureDetail.put("parameters", featureParameters);
+          Multimap<String, String> featureParams = featureSpec.getParams();
+          for (String paramName : featureParams.keySet()) {
+            featureParameters.put(paramName, featureParams.get(paramName));
+          }
+          featureDetailList.put(featureSpec.getName(), featureDetail);
+        }
+        
         // Links
         JSONObject links = new JSONObject();
         for (LinkSpec link : prefs.getLinks().values()) {
@@ -202,6 +220,7 @@ public class JsonRpcHandler {
                   .put("titleUrl", prefs.getTitleUrl().toString())
                   .put("views", views)
                   .put("features", features)
+                  .put("featureDetails", featureDetailList)
                   .put("userPrefs", userPrefs)
                   .put("links", links)
 


Reply via email to