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/13 09:40:33 UTC
svn commit: r985116 [2/2] - in /shindig/trunk: content/container/
extras/src/main/javascript/features-extras/
extras/src/main/javascript/features-extras/org.openajax.hub-2.0.3/
extras/src/main/javascript/features-extras/pubsub-2/
java/gadgets/src/main/...
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)