You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by dd...@apache.org on 2012/01/13 18:59:32 UTC
svn commit: r1231211 - in /shindig/trunk:
content/samplecontainer/examples/commoncontainer/
features/src/main/javascript/features/container.gadget/
features/src/main/javascript/features/container.util/
features/src/main/javascript/features/container/ f...
Author: ddumont
Date: Fri Jan 13 17:59:32 2012
New Revision: 1231211
URL: http://svn.apache.org/viewvc?rev=1231211&view=rev
Log:
SHINDIG-1681 Implement Container token Refresh and moduleId capability for gadget tokens.
Added:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleIdManager.java (with props)
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleIdManagerImpl.java (with props)
Modified:
shindig/trunk/content/samplecontainer/examples/commoncontainer/assembler.js
shindig/trunk/features/src/main/javascript/features/container.gadget/gadget_holder.js
shindig/trunk/features/src/main/javascript/features/container.gadget/gadget_site.js
shindig/trunk/features/src/main/javascript/features/container.util/constant.js
shindig/trunk/features/src/main/javascript/features/container.util/feature.xml
shindig/trunk/features/src/main/javascript/features/container.util/util.js
shindig/trunk/features/src/main/javascript/features/container/container.js
shindig/trunk/features/src/main/javascript/features/container/feature.xml
shindig/trunk/features/src/main/javascript/features/container/service.js
shindig/trunk/features/src/test/javascript/features/container/gadget_holder_test.js
shindig/trunk/features/src/test/javascript/features/container/service_test.js
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandler.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerApi.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerServiceTest.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java
Modified: shindig/trunk/content/samplecontainer/examples/commoncontainer/assembler.js
URL: http://svn.apache.org/viewvc/shindig/trunk/content/samplecontainer/examples/commoncontainer/assembler.js?rev=1231211&r1=1231210&r2=1231211&view=diff
==============================================================================
--- shindig/trunk/content/samplecontainer/examples/commoncontainer/assembler.js (original)
+++ shindig/trunk/content/samplecontainer/examples/commoncontainer/assembler.js Fri Jan 13 17:59:32 2012
@@ -25,16 +25,20 @@ var testConfig = testConfig || {};
testConfig[osapi.container.ServiceConfig.API_PATH] = contextRoot + '/rpc';
testConfig[osapi.container.ContainerConfig.RENDER_DEBUG] = '1';
+// Default the security token for the container. Using this example security token requires enabling
+// the DefaultSecurityTokenCodec to let UrlParameterAuthenticationHandler create valid security token.
+// 10 seconds is fast, but this is mostly for demonstration purposes.
+testConfig[osapi.container.ContainerConfig.GET_CONTAINER_TOKEN] = function(callback) {
+ console.log('Updating container security token.');
+ callback('john.doe:john.doe:appid:cont:url:0:default', 10);
+};
+
// Create the new CommonContainer
var CommonContainer = new osapi.container.Container(testConfig);
//Gadget site to title id map
var siteToTitleMap = {};
-// Default the security token for the container. Using this example security token requires enabling
-// the DefaultSecurityTokenCodec to let UrlParameterAuthenticationHandler create valid security token.
-shindig.auth.updateSecurityToken('john.doe:john.doe:appid:cont:url:0:default');
-
// Need to pull these from values supplied in the dialog
CommonContainer.init = function() {
Modified: shindig/trunk/features/src/main/javascript/features/container.gadget/gadget_holder.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container.gadget/gadget_holder.js?rev=1231211&r1=1231210&r2=1231211&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container.gadget/gadget_holder.js (original)
+++ shindig/trunk/features/src/main/javascript/features/container.gadget/gadget_holder.js Fri Jan 13 17:59:32 2012
@@ -23,18 +23,19 @@
/**
- * @param {number} siteId The id of site containing this holder.
+ * @param {osapi.container.GadgetSite} site The site containing this holder.
* @param {Element} el The element to render gadgets in.
* @param {string} onGadgetLoad The name of the on load function
* @constructor
*/
-osapi.container.GadgetHolder = function(siteId, el, onGadgetLoad) {
+osapi.container.GadgetHolder = function(site, el, onGadgetLoad) {
+
/**
- * Unique numeric gadget ID.
- * @type {number}
+ * The gadget site that holds this holder
+ * @type {osapi.container.GadgetSite}
* @private
*/
- this.siteId_ = siteId;
+ this.site_ = site;
/**
* The element into which the gadget is rendered.
@@ -183,7 +184,7 @@ osapi.container.GadgetHolder.prototype.s
osapi.container.GadgetHolder.prototype.render = function(
gadgetInfo, viewParams, renderParams) {
this.iframeId_ = osapi.container.GadgetHolder.IFRAME_ID_PREFIX_ +
- this.siteId_;
+ this.site_.getId();
this.gadgetInfo_ = gadgetInfo;
this.viewParams_ = viewParams;
this.renderParams_ = renderParams;
@@ -348,7 +349,7 @@ osapi.container.GadgetHolder.prototype.g
}
// Uniquely identify possibly-same gadgets on a page.
- uri.setQP('mid', String(this.siteId_));
+ uri.setQP('mid', String(this.site_.getModuleId()));
if (!osapi.container.util.isEmptyJson(this.viewParams_)) {
var gadgetParamText = gadgets.json.stringify(this.viewParams_);
Modified: shindig/trunk/features/src/main/javascript/features/container.gadget/gadget_site.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container.gadget/gadget_site.js?rev=1231211&r1=1231210&r2=1231211&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container.gadget/gadget_site.js (original)
+++ shindig/trunk/features/src/main/javascript/features/container.gadget/gadget_site.js Fri Jan 13 17:59:32 2012
@@ -78,6 +78,15 @@ osapi.container.GadgetSite = function(ar
osapi.container.Container.prototype.nextUniqueSiteId_++;
/**
+ * Unique numeric module ID for this gadget instance. A module id is used to
+ * identify persisted instances of gadgets.
+ *
+ * @type {number}
+ * @private
+ */
+ this.moduleId_ = 0;
+
+ /**
* ID of parent gadget.
* @type {string?}
* @private
@@ -168,6 +177,52 @@ osapi.container.GadgetSite.prototype.get
return this.id_;
};
+/**
+ * @return {undefined|null|number} The numerical moduleId of this gadget, if
+ * set. May return null or undefined if not set.
+ */
+osapi.container.GadgetSite.prototype.getModuleId = function() {
+ return this.moduleId_;
+};
+
+/**
+ * If you want to change the moduleId after a gadget has rendered, re-navigate the site.
+ *
+ * @param {string} url This gadget's url (may not yet be accessible in all cases from the holder).
+ * @param {number} mid The numerical moduleId for this gadget to use.
+ * @param {function} opt_callback Optional callback to run when the moduleId is set.
+ * @private
+ */
+osapi.container.GadgetSite.prototype.setModuleId_ = function(url, mid, opt_callback) {
+ if (mid && this.moduleId_ != mid) {
+ var self = this,
+ url = osapi.container.util.buildTokenRequestUrl(url, mid);
+
+ if (!self.service_.getCachedGadgetToken(url)) {
+ // We need to request a security token for this gadget instance.
+ var request = osapi.container.util.newTokenRequest([url]);
+ self.service_.getGadgetToken(request, function(response) {
+ var ttl, mid;
+ if (response && response[url]) {
+ if (ttl = response[url][osapi.container.TokenResponse.TOKEN_TTL]) {
+ self.container_.scheduleRefreshTokens_(ttl);
+ }
+ var mid = response[url][osapi.container.TokenResponse.MODULE_ID];
+ if (mid || mid == 0) {
+ self.moduleId_ = mid;
+ }
+ }
+ if (opt_callback) {
+ opt_callback();
+ }
+ });
+ return;
+ }
+ }
+ if (opt_callback) {
+ opt_callback();
+ }
+};
/**
* Returns the currently-active gadget, the loading gadget if a gadget is
@@ -224,9 +279,12 @@ osapi.container.GadgetSite.prototype.nav
var message = ['Failed to navigate for gadget ', gadgetUrl, '.'].join('');
osapi.container.util.warn(message);
} else {
- self.container_.applyLifecycleCallbacks_(osapi.container.CallbackType.ON_BEFORE_RENDER,
- gadgetInfo);
- self.render(gadgetInfo, viewParams, renderParams);
+ var moduleId = renderParams[osapi.container.RenderParam.MODULE_ID] || 0;
+ self.setModuleId_(gadgetUrl, moduleId, function() {
+ self.container_.applyLifecycleCallbacks_(osapi.container.CallbackType.ON_BEFORE_RENDER,
+ gadgetInfo);
+ self.render(gadgetInfo, viewParams, renderParams);
+ });
}
// Return metadata server response time.
@@ -326,7 +384,7 @@ osapi.container.GadgetSite.prototype.ren
// Load into the double-buffer if there is one.
var el = this.loadingGadgetEl_ || this.currentGadgetEl_;
- this.loadingGadgetHolder_ = new osapi.container.GadgetHolder(this.id_, el,
+ this.loadingGadgetHolder_ = new osapi.container.GadgetHolder(this, el,
this.gadgetOnLoad_);
var localRenderParams = {};
@@ -396,8 +454,10 @@ osapi.container.GadgetSite.prototype.rpc
* @private
*/
osapi.container.GadgetSite.prototype.updateSecurityToken_ =
- function(gadgetInfo, renderParams) {
- var tokenInfo = this.service_.getCachedGadgetToken(gadgetInfo['url']);
+ function(gadgetInfo, renderParams) {
+ var url = osapi.container.util.buildTokenRequestUrl(gadgetInfo['url'], this.moduleId_),
+ tokenInfo = this.service_.getCachedGadgetToken(url);
+
if (tokenInfo) {
var token = tokenInfo[osapi.container.TokenResponse.TOKEN];
this.loadingGadgetHolder_.setSecurityToken(token);
Modified: shindig/trunk/features/src/main/javascript/features/container.util/constant.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container.util/constant.js?rev=1231211&r1=1231210&r2=1231211&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container.util/constant.js (original)
+++ shindig/trunk/features/src/main/javascript/features/container.util/constant.js Fri Jan 13 17:59:32 2012
@@ -66,7 +66,9 @@ osapi.container.MetadataResponse = {
* @enum {string}
*/
osapi.container.TokenResponse = {
- TOKEN: 'token'
+ TOKEN: 'token',
+ TOKEN_TTL: 'tokenTTL',
+ MODULE_ID: 'moduleId'
};
@@ -130,7 +132,13 @@ osapi.container.RenderParam = {
VIEW: 'view',
/** The starting gadget iframe width (in pixels). */
- WIDTH: 'width'
+ WIDTH: 'width',
+
+ /**
+ * The modduleId of this gadget. Used to identify saved instances of gadgets.
+ * Defaults to 0, which means the instance of the gadget is not saved.
+ */
+ MODULE_ID: 'moduleid'
};
/**
@@ -179,3 +187,179 @@ osapi.container.CallbackType = {
/** Name of the global function all gadgets will call when they are loaded. */
GADGET_ON_LOAD: '__gadgetOnLoad'
};
+
+/**
+ * Enumeration of configuration keys for a osapi.container.Container. This is specified in
+ * JSON to provide extensible configuration. These enum values are for
+ * documentation purposes only, it is expected that clients use the string
+ * values.
+ * @enum {string}
+ */
+osapi.container.ContainerConfig = {
+ /**
+ * Allow gadgets to render in unspecified view.
+ * @type {string}
+ * @const
+ */
+ ALLOW_DEFAULT_VIEW: 'allowDefaultView',
+
+ /**
+ * Whether cajole mode is turned on.
+ * @type {string}
+ * @const
+ */
+ RENDER_CAJOLE: 'renderCajole',
+
+ /**
+ * Whether debug mode is turned on.
+ * @type {string}
+ * @const
+ */
+ RENDER_DEBUG: 'renderDebug',
+
+ /**
+ * The debug param name to look for in container URL for per-request debugging.
+ * @type {string}
+ * @const
+ */
+ RENDER_DEBUG_PARAM: 'renderDebugParam',
+
+ /**
+ * Whether test mode is turned on.
+ * @type {string}
+ * @const
+ */
+ RENDER_TEST: 'renderTest',
+
+ /**
+ * Security token refresh interval (in ms). Set to 0 in config to disable
+ * token refresh.
+ *
+ * This number should always be >= 0. The smallest encountered token ttl or this
+ * number will be used as the refresh interval, whichever is smaller.
+ *
+ * @type {string}
+ * @const
+ */
+ TOKEN_REFRESH_INTERVAL: 'tokenRefreshInterval',
+
+ /**
+ * Globally-defined callback function upon gadget navigation. Useful to
+ * broadcast timing and stat information back to container.
+ * @type {string}
+ * @const
+ */
+ NAVIGATE_CALLBACK: 'navigateCallback',
+
+ /**
+ * Provide server reference time for preloaded data.
+ * This time is used instead of each response time in order to support server
+ * caching of results.
+ * @type {number}
+ * @const
+ */
+ PRELOAD_REF_TIME: 'preloadRefTime',
+
+ /**
+ * Preloaded hash of gadgets metadata
+ * @type {Object}
+ * @const
+ */
+ PRELOAD_METADATAS: 'preloadMetadatas',
+
+ /**
+ * Preloaded hash of gadgets tokens
+ * @type {Object}
+ * @const
+ */
+ PRELOAD_TOKENS: 'preloadTokens',
+
+ /**
+ * Used to query the language locale part of the container page.
+ * @type {function}
+ */
+ GET_LANGUAGE: 'GET_LANGUAGE',
+
+ /**
+ * Used to query the country locale part of the container page.
+ * @type {function}
+ */
+ GET_COUNTRY: 'GET_COUNTRY',
+
+ /**
+ * Used to retrieve the persisted preferences for a gadget.
+ * @type {function}
+ */
+ GET_PREFERENCES: 'GET_PREFERENCES',
+
+ /**
+ * Used to persist preferences for a gadget.
+ * @type {function}
+ */
+ SET_PREFERENCES: 'SET_PREFERENCES',
+
+ /**
+ * Used to arbitrate RPC calls.
+ * @type {function}
+ */
+ RPC_ARBITRATOR: 'rpcArbitrator',
+
+ /**
+ * Used to retrieve security tokens for gadgets.
+ * @type {function}
+ */
+ GET_GADGET_TOKEN: 'GET_GADGET_TOKEN',
+
+ /**
+ * Used to retrieve a security token for the container.
+ * Containers who specify this config value can call
+ * CommonContainer.updateContainerSecurityToken after the creation of the
+ * common container to start the scheduling of container token refreshes.
+ *
+ * @type {function(function)=}
+ * @param {function(String, number)} callback The function to call to report
+ * the updated token and the token's new time-to-live in seconds. This
+ * callback function must be called with unspecified values in the event of
+ * an error.
+ *
+ * The first and second arguments to this callback function are the same as
+ * the second and third arguments to:
+ * osapi.container.Container.prototype.updateContainerSecurityToken
+ * Example:
+ * <code>
+ * var config = {};
+ * config[osapi.container.ContainerConfig.GET_CONTAINER_TOKEN] = function(result) {
+ * var token, ttl, error = false;
+ * // Do work to set token and ttl values
+ * if (error) {
+ * result();
+ * } else {
+ * result(token, ttl);
+ * }
+ * };
+ * </code>
+ * @see osapi.container.Container.prototype.updateContainerSecurityToken
+ */
+ GET_CONTAINER_TOKEN: 'GET_CONTAINER_TOKEN'
+};
+
+/**
+ * Enumeration of configuration keys for a osapi.container.Service. This is specified in
+ * JSON to provide extensible configuration.
+ * @enum {string}
+ */
+osapi.container.ServiceConfig = {
+ /**
+ * Host to fetch gadget information, via XHR.
+ * @type {string}
+ * @const
+ */
+ API_HOST: 'apiHost',
+
+ /**
+ * Path to fetch gadget information, via XHR.
+ * @type {string}
+ * @const
+ */
+ API_PATH: 'apiPath'
+}
\ No newline at end of file
Modified: shindig/trunk/features/src/main/javascript/features/container.util/feature.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container.util/feature.xml?rev=1231211&r1=1231210&r2=1231211&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container.util/feature.xml (original)
+++ shindig/trunk/features/src/main/javascript/features/container.util/feature.xml Fri Jan 13 17:59:32 2012
@@ -39,6 +39,30 @@ specific language governing permissions
<exports type="js">osapi.container.RenderParam.USER_PREFS</exports>
<exports type="js">osapi.container.RenderParam.VIEW</exports>
<exports type="js">osapi.container.RenderParam.WIDTH</exports>
+ <exports type="js">osapi.container.RenderParam.MODULE_ID</exports>
+
+ <exports type="js">osapi.container.ViewParam.VIEW</exports>
+
+ <exports type="js">osapi.container.ContainerConfig.ALLOW_DEFAULT_VIEW</exports>
+ <exports type="js">osapi.container.ContainerConfig.RENDER_CAJOLE</exports>
+ <exports type="js">osapi.container.ContainerConfig.RENDER_DEBUG</exports>
+ <exports type="js">osapi.container.ContainerConfig.RENDER_DEBUG_PARAM</exports>
+ <exports type="js">osapi.container.ContainerConfig.RENDER_TEST</exports>
+ <exports type="js">osapi.container.ContainerConfig.TOKEN_REFRESH_INTERVAL</exports>
+ <exports type="js">osapi.container.ContainerConfig.NAVIGATE_CALLBACK</exports>
+ <exports type="js">osapi.container.ContainerConfig.PRELOAD_REF_TIME</exports>
+ <exports type="js">osapi.container.ContainerConfig.PRELOAD_METADATAS</exports>
+ <exports type="js">osapi.container.ContainerConfig.PRELOAD_TOKENS</exports>
+ <exports type="js">osapi.container.ContainerConfig.GET_LANGUAGE</exports>
+ <exports type="js">osapi.container.ContainerConfig.GET_COUNTRY</exports>
+ <exports type="js">osapi.container.ContainerConfig.GET_PREFERENCES</exports>
+ <exports type="js">osapi.container.ContainerConfig.SET_PREFERENCES</exports>
+ <exports type="js">osapi.container.ContainerConfig.RPC_ARBITRATOR</exports>
+ <exports type="js">osapi.container.ContainerConfig.GET_GADGET_TOKEN</exports>
+ <exports type="js">osapi.container.ContainerConfig.GET_CONTAINER_TOKEN</exports>
+
+ <exports type="js">osapi.container.ServiceConfig.API_HOST</exports>
+ <exports type="js">osapi.container.ServiceConfig.API_PATH</exports>
</api>
</container>
</feature>
\ No newline at end of file
Modified: shindig/trunk/features/src/main/javascript/features/container.util/util.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container.util/util.js?rev=1231211&r1=1231210&r2=1231211&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container.util/util.js (original)
+++ shindig/trunk/features/src/main/javascript/features/container.util/util.js Fri Jan 13 17:59:32 2012
@@ -101,7 +101,9 @@ osapi.container.util.newTokenRequest = f
'container': window.__CONTAINER,
'ids': gadgetUrls,
'fields': [
- 'token'
+ 'token',
+ 'tokenTTL',
+ 'moduleId'
]
};
};
@@ -162,7 +164,7 @@ osapi.container.util.getCurrentTimeMs =
};
/**
- * Crates the HTML for the iFrame
+ * Creates the HTML for the iFrame
* @param {Object.<string,string>} iframeParams iframe Params.
* @return {string} the HTML for the iFrame.
*/
@@ -187,3 +189,18 @@ osapi.container.util.createIframeHtml =
return out.join('');
};
+
+/**
+ * Constructs a url for token refresh given a gadgetUrl and moduleId.
+ *
+ * @param {string} url The gadget's url
+ * @param {number} moduleId A moduleId.
+ * @return {string} A url to use in a TokenRequest for a security token.
+ */
+osapi.container.util.buildTokenRequestUrl = function(url, moduleId) {
+ url = shindig.uri(url);
+ if (moduleId) {
+ url.setFragment(moduleId);
+ }
+ return url.toString();
+};
Modified: shindig/trunk/features/src/main/javascript/features/container/container.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container/container.js?rev=1231211&r1=1231210&r2=1231211&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container/container.js (original)
+++ shindig/trunk/features/src/main/javascript/features/container/container.js Fri Jan 13 17:59:32 2012
@@ -103,12 +103,7 @@ osapi.container.Container = function(opt
osapi.container.ContainerConfig.RENDER_TEST, false));
/**
- * Security token refresh interval (in ms). Set to < 0 in config to disable
- * token refresh.
- *
- * Provided this number is >= 0, the smallest encountered token ttl or this
- * number will be used as the refresh interval, whichever is smaller.
- *
+ * @see osapi.container.ContainerConfig.TOKEN_REFRESH_INTERVAL
* @type {number}
* @private
*/
@@ -134,10 +129,10 @@ osapi.container.Container = function(opt
* @type {osapi.container.Service}
* @private
*/
- this.service_ = new osapi.container.Service(config);
+ this.service_ = new osapi.container.Service(this);
/**
- * result from calling window.setInterval()
+ * result from calling window.setTimeout()
* @type {?number}
* @private
*/
@@ -222,7 +217,6 @@ osapi.container.Container.prototype.navi
var
self = this,
- selfSite = site,
finishNavigate = function(preferences) {
renderParams[RenderParam.USER_PREFS] = preferences;
self.applyLifecycleCallbacks_(osapi.container.CallbackType.ON_BEFORE_NAVIGATE,
@@ -239,8 +233,7 @@ osapi.container.Container.prototype.navi
self.scheduleRefreshTokens_(gadgetInfo[osapi.container.MetadataResponse.TOKEN_TTL]);
}
- self.applyLifecycleCallbacks_(osapi.container.CallbackType.ON_NAVIGATED,
- selfSite);
+ self.applyLifecycleCallbacks_(osapi.container.CallbackType.ON_NAVIGATED, site);
callback(gadgetInfo);
});
};
@@ -413,114 +406,6 @@ osapi.container.Container.addMixin = fun
// -----------------------------------------------------------------------------
-// Valid JSON keys.
-// -----------------------------------------------------------------------------
-
-/**
- * Enumeration of configuration keys for this container. This is specified in
- * JSON to provide extensible configuration. These enum values are for
- * documentation purposes only, it is expected that clients use the string
- * values.
- * @enum {string}
- */
-osapi.container.ContainerConfig = {};
-/**
- * Allow gadgets to render in unspecified view.
- * @type {string}
- * @const
- */
-osapi.container.ContainerConfig.ALLOW_DEFAULT_VIEW = 'allowDefaultView';
-/**
- * Whether cajole mode is turned on.
- * @type {string}
- * @const
- */
-osapi.container.ContainerConfig.RENDER_CAJOLE = 'renderCajole';
-/**
- * Whether debug mode is turned on.
- * @type {string}
- * @const
- */
-osapi.container.ContainerConfig.RENDER_DEBUG = 'renderDebug';
-/**
- * The debug param name to look for in container URL for per-request debugging.
- * @type {string}
- * @const
- */
-osapi.container.ContainerConfig.RENDER_DEBUG_PARAM = 'renderDebugParam';
-/**
- * Whether test mode is turned on.
- * @type {string}
- * @const
- */
-osapi.container.ContainerConfig.RENDER_TEST = 'renderTest';
-/**
- * Security token refresh interval (in ms) for debugging.
- * @type {string}
- * @const
- */
-osapi.container.ContainerConfig.TOKEN_REFRESH_INTERVAL = 'tokenRefreshInterval';
-/**
- * Globally-defined callback function upon gadget navigation. Useful to
- * broadcast timing and stat information back to container.
- * @type {string}
- * @const
- */
-osapi.container.ContainerConfig.NAVIGATE_CALLBACK = 'navigateCallback';
-
-/**
- * Provide server reference time for preloaded data.
- * This time is used instead of each response time in order to support server
- * caching of results.
- * @type {number}
- * @const
- */
-osapi.container.ContainerConfig.PRELOAD_REF_TIME = 'preloadRefTime';
-/**
- * Preloaded hash of gadgets metadata
- * @type {Object}
- * @const
- */
-osapi.container.ContainerConfig.PRELOAD_METADATAS = 'preloadMetadatas';
-/**
- * Preloaded hash of gadgets tokens
- * @type {Object}
- * @const
- */
-osapi.container.ContainerConfig.PRELOAD_TOKENS = 'preloadTokens';
-/**
- * Used to query the language locale part of the container page.
- * @type {function}
- */
-osapi.container.ContainerConfig.GET_LANGUAGE = 'GET_LANGUAGE';
-/**
- * Used to query the country locale part of the container page.
- * @type {function}
- */
-osapi.container.ContainerConfig.GET_COUNTRY = 'GET_COUNTRY';
-/**
- * Used to retrieve the persisted preferences for a gadget.
- * @type {function}
- */
-osapi.container.ContainerConfig.GET_PREFERENCES = 'GET_PREFERENCES';
-/**
- * Used to persist preferences for a gadget.
- * @type {function}
- */
-osapi.container.ContainerConfig.SET_PREFERENCES = 'SET_PREFERENCES';
-/**
- * Used to arbitrate RPC calls.
- * @type {function}
- */
-osapi.container.ContainerConfig.RPC_ARBITRATOR = 'rpcArbitrator';
-/**
- * Used to retrieve security tokens for gadgets.
- * @type {function}
- */
-osapi.container.ContainerConfig.GET_GADGET_TOKEN = 'GET_GADGET_TOKEN';
-
-
-// -----------------------------------------------------------------------------
// Private variables and methods.
// -----------------------------------------------------------------------------
@@ -624,6 +509,22 @@ osapi.container.Container.prototype.getS
};
/**
+ * Update and schedule refreshing of container token. This function will use the config function
+ * osapi.container.ContainerConfig.GET_CONTAINER_TOKEN to fetch a container token, if needed,
+ * unless the token is specified in the optional parameter, in which case the token will be
+ * updated with the provided value immediately.
+ *
+ * @param {function=} callback Function to run when container token is valid.
+ * @param {String=} token The containers new security token.
+ * @param {number=} ttl The token's ttl in seconds. If token is specified and ttl is 0,
+ * token refresh will be disabled.
+ * @see osapi.container.ContainerConfig.GET_CONTAINER_TOKEN (constants.js)
+ */
+osapi.container.Container.prototype.updateContainerSecurityToken = function(callback, token, ttl) {
+ this.service_.updateContainerSecurityToken(callback, token, ttl);
+}
+
+/**
* Start to schedule refreshing of tokens.
* @param {number} Encountered token time to live in seconds.
* @private
@@ -633,12 +534,14 @@ osapi.container.Container.prototype.sche
oldInterval = this.tokenRefreshInterval_,
newInterval = tokenTTL ? this.setRefreshTokenInterval_(tokenTTL * 1000) : oldInterval,
refresh = function() {
- self.lastRefresh_ = osapi.container.util.getCurrentTimeMs();
- // Schedule the next refresh.
- self.tokenRefreshTimer_ = setTimeout(refresh, newInterval);
-
- // Do this last so that if it ever errors, we maintain the refresh schedule.
- self.refreshTokens_();
+ self.updateContainerSecurityToken(function() {
+ self.lastRefresh_ = osapi.container.util.getCurrentTimeMs();
+ // Schedule the next refresh.
+ self.tokenRefreshTimer_ = setTimeout(refresh, newInterval);
+
+ // Do this last so that if it ever errors, we maintain the refresh schedule.
+ self.refreshTokens_();
+ });
};
// If enabled, check to see if we no schedule or if the two intervals are different and update the schedule.
@@ -675,7 +578,7 @@ osapi.container.Container.prototype.unsc
if (this.tokenRefreshTimer_) {
var urls = this.getTokenRefreshableGadgetUrls_();
if (urls.length <= 0) {
- window.clearInterval(this.tokenRefreshTimer_);
+ clearTimeout(this.tokenRefreshTimer_);
this.tokenRefreshTimer_ = null;
}
}
@@ -809,14 +712,47 @@ osapi.container.Container.prototype.addP
* @return {Array} An array of URLs of gadgets.
* @private
*/
+// TODO: this function needs to be renamed, perhaps: getTokenRequestUrls_
osapi.container.Container.prototype.getTokenRefreshableGadgetUrls_ = function() {
var result = {};
+
for (var url in this.getActiveGadgetUrls_()) {
var metadata = this.service_.getCachedGadgetMetadata(url);
if (metadata[osapi.container.MetadataResponse.NEEDS_TOKEN_REFRESH]) {
- result[url] = null;
+ result[url] = 1;
}
}
+
+ /* Now add all gadget site urls that have moduleIds
+ *
+ * We're basically refreshing a security token for any given
+ * non-persisted (no moduleId) navigated or preloaded gadget instance, as
+ * well as each persisted instance (each moduleId) for any given gadgetUrl.
+ *
+ * In other words, if we've got a gadget preloaded or navigated:
+ * http://foo.com/gadget.xml
+ * We will refresh a token for non-persisted (no moduleId) instances of that
+ * gadget.
+ * If we've got a navigated persisted gadget on the page, we'll refresh that
+ * security token as well.
+ */
+ for (var siteId in this.sites_) {
+ var site = this.sites_[siteId];
+ if (site instanceof osapi.container.GadgetSite) {
+ var holder = site.getActiveGadgetHolder();
+ if (holder) {
+ var url = holder.getUrl();
+ mid = site.getModuleId();
+
+ // If this gadget token does not require refresh
+ // (baseurl is not already in result), don't add it.
+ if (result[url]) {
+ result[osapi.container.util.buildTokenRequestUrl(url, mid)] = 1;
+ }
+ }
+ }
+ }
+
return osapi.container.util.toArrayOfJsonKeys(result);
};
@@ -843,9 +779,9 @@ osapi.container.Container.prototype.getN
for (var siteId in this.sites_) {
var site = this.sites_[siteId];
if (site instanceof osapi.container.GadgetSite) {
- var holder = (site.getActiveGadgetHolder || site.getActiveUrlHolder).call(site);
+ var holder = site.getActiveGadgetHolder(site);
if(holder) {
- result[holder.getUrl()] = null;
+ result[holder.getUrl()] = 1;
}
}
}
@@ -868,14 +804,18 @@ osapi.container.Container.prototype.refr
// update pre-loaded gadgets, since new tokens will take effect when they
// are navigated to, from cache.
for (var siteId in self.sites_) {
- if (self.sites_[siteId] instanceof osapi.container.GadgetSite) {
- var holder = self.sites_[siteId].getActiveGadgetHolder();
+ var site = self.sites_[siteId];
+ if (site instanceof osapi.container.GadgetSite) {
+ var holder = site.getActiveGadgetHolder();
var gadgetInfo = self.service_.getCachedGadgetMetadata(holder.getUrl());
if (gadgetInfo[osapi.container.MetadataResponse.NEEDS_TOKEN_REFRESH]) {
- var tokenInfo = response[holder.getUrl()];
+ var mid = site.getModuleId(),
+ url = osapi.container.util.buildTokenRequestUrl(holder.getUrl(), mid),
+ tokenInfo = response[url];
+
if (tokenInfo.error) {
gadgets.warn(['Failed to get token for gadget ',
- holder.getUrl(), '.'].join(''));
+ url, '.'].join(''));
} else {
gadgets.rpc.call(holder.getIframeId(), 'update_security_token', null,
tokenInfo[osapi.container.TokenResponse.TOKEN]);
Modified: shindig/trunk/features/src/main/javascript/features/container/feature.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container/feature.xml?rev=1231211&r1=1231210&r2=1231211&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container/feature.xml (original)
+++ shindig/trunk/features/src/main/javascript/features/container/feature.xml Fri Jan 13 17:59:32 2012
@@ -46,16 +46,7 @@ under the License.
<exports type="js">osapi.container.Container.prototype.rpcRegister</exports>
<exports type="js">osapi.container.Container.prototype.onConstructed</exports>
<exports type="js">osapi.container.Container.prototype.getGadgetSiteById</exports>
- <exports type="js">osapi.container.ContainerConfig.ALLOW_DEFAULT_VIEW</exports>
- <exports type="js">osapi.container.ContainerConfig.RENDER_CAJOLE</exports>
- <exports type="js">osapi.container.ContainerConfig.RENDER_DEBUG</exports>
- <exports type="js">osapi.container.ContainerConfig.RENDER_DEBUG_PARAM</exports>
- <exports type="js">osapi.container.ContainerConfig.RENDER_TEST</exports>
- <exports type="js">osapi.container.ContainerConfig.TOKEN_REFRESH_INTERVAL</exports>
- <exports type="js">osapi.container.ContainerConfig.NAVIGATE_CALLBACK</exports>
- <exports type="js">osapi.container.ContainerConfig.PRELOAD_REF_TIME</exports>
- <exports type="js">osapi.container.ContainerConfig.PRELOAD_METADATAS</exports>
- <exports type="js">osapi.container.ContainerConfig.PRELOAD_TOKENS</exports>
+ <exports type="js">osapi.container.Container.prototype.updateContainerSecurityToken</exports>
<exports type="rpc">resize_iframe</exports>
<exports type="rpc">resize_iframe_width</exports>
<exports type="rpc">set_pref</exports>
Modified: shindig/trunk/features/src/main/javascript/features/container/service.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container/service.js?rev=1231211&r1=1231210&r2=1231211&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container/service.js (original)
+++ shindig/trunk/features/src/main/javascript/features/container/service.js Fri Jan 13 17:59:32 2012
@@ -24,11 +24,18 @@
/**
- * @param {Object=} opt_config Configuration JSON.
+ * @param {osapi.container.Container} The container that this service services.
* @constructor
*/
-osapi.container.Service = function(opt_config) {
- var config = this.config_ = opt_config || {};
+osapi.container.Service = function(container) {
+ /**
+ * The container that this service services.
+ * @type {osapi.container.Container}
+ * @private
+ */
+ this.container_ = container;
+
+ var config = this.config_ = container.config_ || {};
var injectedEndpoint = ((gadgets.config.get('osapi') || {}).endPoints ||
[window.__API_URI.getOrigin() + '/rpc'])[0];
@@ -118,31 +125,31 @@ osapi.container.Service.prototype.getGad
request['ids'] = uncachedUrls;
request['language'] = this.getLanguage();
request['country'] = this.getCountry();
- osapi['gadgets']['metadata'](request).execute(function(response) {
-
- // If response entirely fails, augment individual errors.
- if (response['error']) {
- for (var i = 0; i < request['ids'].length; i++) {
- finalResponse[id] = { 'error' : response['error'] };
+ this.updateContainerSecurityToken(function() {
+ osapi['gadgets']['metadata'](request).execute(function(response) {
+ // If response entirely fails, augment individual errors.
+ if (response['error']) {
+ for (var i = 0; i < request['ids'].length; i++) {
+ finalResponse[id] = { 'error' : response['error'] };
+ }
+
+ // Otherwise, cache response. Augment final response with server response.
+ } else {
+ var currentTimeMs = osapi.container.util.getCurrentTimeMs();
+ for (var id in response) {
+ var resp = response[id];
+ self.updateResponse_(resp, id, currentTimeMs);
+ self.cachedMetadatas_[id] = resp;
+ finalResponse[id] = resp;
+ }
}
- // Otherwise, cache response. Augment final response with server response.
- } else {
- var currentTimeMs = osapi.container.util.getCurrentTimeMs();
- for (var id in response) {
- var resp = response[id];
- self.updateResponse_(resp, id, currentTimeMs);
- self.cachedMetadatas_[id] = resp;
- finalResponse[id] = resp;
- }
- }
-
- callback(finalResponse);
+ callback(finalResponse);
+ });
});
}
};
-
/**
* Add preloaded gadgets to cache
* @param {Object} response hash of gadgets metadata.
@@ -222,8 +229,11 @@ osapi.container.Service.prototype.getGad
// Otherwise, cache response. Augment final response with server response.
} else {
for (var id in response) {
- response[id]['url'] = id; // make sure url is set
- self.cachedTokens_[id] = response[id];
+ var mid = response[osapi.container.TokenResponse.MODULE_ID],
+ url = osapi.container.util.buildTokenRequestUrl(id, mid);
+
+ //response[id]['url'] = id; // make sure url is set
+ self.cachedTokens_[url] = response[id];
finalResponse[id] = response[id];
}
}
@@ -232,11 +242,13 @@ osapi.container.Service.prototype.getGad
};
// If we have a custom token fetch function, call it -- otherwise use the default
- if (this.config_[osapi.container.ContainerConfig.GET_GADGET_TOKEN]) {
- this.config_[osapi.container.ContainerConfig.GET_GADGET_TOKEN](request, tokenResponseCallback);
- } else {
- osapi['gadgets']['token'](request).execute(tokenResponseCallback);
- }
+ self.updateContainerSecurityToken(function() {
+ if (self.config_[osapi.container.ContainerConfig.GET_GADGET_TOKEN]) {
+ self.config_[osapi.container.ContainerConfig.GET_GADGET_TOKEN](request, tokenResponseCallback);
+ } else {
+ osapi['gadgets']['token'](request).execute(tokenResponseCallback);
+ }
+ });
};
@@ -388,29 +400,89 @@ osapi.container.Service.prototype.getCou
}
};
+/**
+ * Container Token Refresh
+ */
+(function() {
+ var containerTimeout, lastRefresh, fetching,
+ containerTokenTTL = 1800000 * 0.8, // 30 min default token ttl
+ callbacks = [];
+
+
+ function runCallbacks(callbacks) {
+ while (callbacks.length) {
+ callbacks.shift().call(null); // Window context
+ }
+ }
-// -----------------------------------------------------------------------------
-// Configuration
-// -----------------------------------------------------------------------------
+ function refresh(fetch_once) {
+ fetching = true;
+ if (containerTimeout) {
+ clearTimeout(containerTimeout);
+ containerTimeout = 0;
+ }
+ var fetch = fetch_once || this.config_[osapi.container.ContainerConfig.GET_CONTAINER_TOKEN];
+ if (fetch) {
+ var self = this;
+ fetch(function(token, ttl) { // token and ttl may be undefined in the case of an error
+ fetching = false;
+
+ // Use last known ttl if there was an error
+ containerTokenTTL = token ? (ttl * 1000 * 0.8) : containerTokenTTL;
+ if (containerTokenTTL) {
+ // Refresh again in 80% of the reported ttl
+ containerTimeout = setTimeout(gadgets.util.makeClosure(this, refresh), containerTokenTTL);
+ }
-/**
- * Enumeration of configuration keys for this service. This is specified in
- * JSON to provide extensible configuration.
- * @enum {string}
- */
-osapi.container.ServiceConfig = {};
+ if (token) {
+ // Looks like everything worked out... let's update the token.
+ shindig.auth.updateSecurityToken(token);
+ lastRefresh = osapi.container.util.getCurrentTimeMs();
+ // And then run all the callbacks waiting for this.
+ runCallbacks(callbacks);
+ }
+ });
+ } else {
+ fetching = false;
+ // Fail gracefully, container supplied no fetch function. Do not hold on to callbacks.
+ runCallbacks(callbacks);
+ }
+ }
-/**
- * Host to fetch gadget information, via XHR.
- * @type {string}
- * @const
- */
-osapi.container.ServiceConfig.API_HOST = 'apiHost';
+ /**
+ * @see osapi.container.Container.prototype.updateContainerSecurityToken
+ */
+ osapi.container.Service.prototype.updateContainerSecurityToken = function(callback, token, ttl) {
+ var now = osapi.container.util.getCurrentTimeMs(),
+ needsRefresh = containerTokenTTL &&
+ (fetching || token || !lastRefresh || now > lastRefresh + containerTokenTTL);
+ if (needsRefresh) {
+ // Hard expire in 95% of originial ttl.
+ var expired = !lastRefresh || now > lastRefresh + (containerTokenTTL * 95 / 80);
+ if (!expired && callback) {
+ // Token not expired, but needs refresh. Don't block operations that need a valid token.
+ callback();
+ } else if (callback) {
+ // We have a callback, there's either a fetch happening, or we otherwise need to refresh the
+ // token. Place it in the callbacks queue to be run after the fetch (currently running or
+ // soon to be launched) completes.
+ callbacks.push(callback);
+ }
-/**
- * Path to fetch gadget information, via XHR.
- * @type {string}
- * @const
- */
-osapi.container.ServiceConfig.API_PATH = 'apiPath';
+ if (token) {
+ // We are trying to set a token initially. Run refresh with a fetch_once function that simply
+ // returns the canned values. Then schedule the refresh using the function in the config
+ refresh.call(this, function(result) {
+ result(token, ttl);
+ });
+ } else if (!fetching) {
+ // There's no fetch going on right now. We need to start one because the token needs a refresh
+ refresh.call(this);
+ }
+ } else if (callback) {
+ // No refresh needed, run the callback because the token is fine.
+ callback();
+ }
+ };
+})();
\ No newline at end of file
Modified: shindig/trunk/features/src/test/javascript/features/container/gadget_holder_test.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/test/javascript/features/container/gadget_holder_test.js?rev=1231211&r1=1231210&r2=1231211&view=diff
==============================================================================
--- shindig/trunk/features/src/test/javascript/features/container/gadget_holder_test.js (original)
+++ shindig/trunk/features/src/test/javascript/features/container/gadget_holder_test.js Fri Jan 13 17:59:32 2012
@@ -41,8 +41,14 @@ GadgetHolderTest.prototype.tearDown = fu
};
GadgetHolderTest.prototype.testNew = function() {
- var element = {};
- var holder = new osapi.container.GadgetHolder(123, element);
+ var element = {
+ getAttribute: function() {
+ return '0';
+ },
+ id: '123'
+ };
+ var site = new osapi.container.GadgetSite({gadgetEl: element});
+ var holder = new osapi.container.GadgetHolder(site, element);
this.assertEquals(element, holder.getElement());
this.assertNull(holder.getIframeId());
this.assertNull(holder.getGadgetInfo());
@@ -56,7 +62,11 @@ GadgetHolderTest.prototype.testRenderWit
'url' : 'gadget.xml'
};
this.setupGadgetsRpcSetupReceiver();
- var holder = new osapi.container.GadgetHolder(123, element, '__gadgetOnLoad');
+ var element = {
+ id: '123'
+ };
+ var site = new osapi.container.GadgetSite({gadgetEl: element});
+ var holder = new osapi.container.GadgetHolder(site, element, '__gadgetOnLoad');
holder.render(gadgetInfo, {}, {});
this.assertEquals('<iframe' +
' marginwidth="0"' +
@@ -69,13 +79,12 @@ GadgetHolderTest.prototype.testRenderWit
' id="__gadget_123"' +
' name="__gadget_123"' +
' src="http://shindig/gadgets/ifr?url=gadget.xml&debug=0&nocache=0&testmode=0' +
- '&parent=http%3A//container.com&mid=123"' +
+ '&parent=http%3A//container.com&mid=0"' +
' ></iframe>',
element.innerHTML);
};
GadgetHolderTest.prototype.testRenderWithRenderRequests = function() {
- var element = {};
var gadgetInfo = {
'iframeUrl' : 'http://shindig/gadgets/ifr?url=gadget.xml',
'url' : 'gadget.xml'
@@ -90,7 +99,11 @@ GadgetHolderTest.prototype.testRenderWit
'width' : 222
};
this.setupGadgetsRpcSetupReceiver();
- var holder = new osapi.container.GadgetHolder(123, element, '__gadgetOnLoad');
+ var element = {
+ id: '123'
+ };
+ var site = new osapi.container.GadgetSite({gadgetEl: element, moduleId: 123});
+ var holder = new osapi.container.GadgetHolder(site, element, '__gadgetOnLoad');
holder.render(gadgetInfo, {}, renderParams);
this.assertEquals('<iframe' +
' marginwidth="0"' +
@@ -106,7 +119,7 @@ GadgetHolderTest.prototype.testRenderWit
' width="222"' +
' name="__gadget_123"' +
' src="http://shindig/gadgets/ifr?url=gadget.xml&debug=1&nocache=1&testmode=1' +
- '&libs=caja&caja=1&parent=http%3A//container.com&mid=123"' +
+ '&libs=caja&caja=1&parent=http%3A//container.com&mid=0"' +
' ></iframe>',
element.innerHTML);
};
Modified: shindig/trunk/features/src/test/javascript/features/container/service_test.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/test/javascript/features/container/service_test.js?rev=1231211&r1=1231210&r2=1231211&view=diff
==============================================================================
--- shindig/trunk/features/src/test/javascript/features/container/service_test.js (original)
+++ shindig/trunk/features/src/test/javascript/features/container/service_test.js Fri Jan 13 17:59:32 2012
@@ -32,9 +32,15 @@ ServiceTest.inherits(TestCase);
ServiceTest.prototype.setUp = function() {
this.apiUri = window.__API_URI;
window.__API_URI = shindig.uri('http://shindig.com');
- this.container = window.__CONTAINER;
- window.__CONTAINER = "best_container";
+ this.containerUri = window.__CONTAINER_URI;
+ window.__CONTAINER_URI = shindig.uri('http://container.com');
this.osapiGadgets = osapi.gadgets;
+ this.shindigContainerGadgetSite = osapi.container.GadgetSite;
+ this.gadgetsRpc = gadgets.rpc;
+ gadgets.rpc = {
+ register: function() {
+ }
+ };
this.self = {};
var response = {};
@@ -43,7 +49,9 @@ ServiceTest.prototype.setUp = function()
ServiceTest.prototype.tearDown = function() {
window.__API_URI = this.apiUri;
- window.__CONTAINER = this.container;
+ window.__CONTAINER_URI = this.containerUri;
+ osapi.container.GadgetSite = this.shindigContainerGadgetSite;
+ gadgets.rpc = this.gadgetsRpc;
osapi.gadgets = this.osapiGadgets;
};
@@ -65,14 +73,14 @@ ServiceTest.prototype.setupUtilCurrentTi
};
ServiceTest.prototype.testGetGadgetMetadata = function() {
- var service = new osapi.container.Service({
+ var service = new osapi.container.Service(new osapi.container.Container({
GET_LANGUAGE: function() {
return 'pt';
},
GET_COUNTRY: function() {
return 'BR';
}
- });
+ }));
service.cachedMetadatas_ = {
'cached1.xml' : {
'url' : 'cached1.xml',
@@ -143,7 +151,7 @@ ServiceTest.prototype.testGetGadgetMetad
};
ServiceTest.prototype.testUncacheStaleGadgetMetadataExcept = function() {
- var service = new osapi.container.Service();
+ var service = new osapi.container.Service(new osapi.container.Container());
service.cachedMetadatas_ = {
'cached1.xml' : { 'localExpireTimeMs' : 100 },
'cached2.xml' : { 'localExpireTimeMs' : 200 },
@@ -162,7 +170,7 @@ ServiceTest.prototype.testUncacheStaleGa
};
ServiceTest.prototype.testUpdateResponse = function() {
- var service = new osapi.container.Service();
+ var service = new osapi.container.Service(new osapi.container.Container());
this.setupUtilCurrentTimeMs(120);
var data = {responseTimeMs : 100, expireTimeMs : 105};
@@ -177,7 +185,7 @@ ServiceTest.prototype.testUpdateResponse
};
ServiceTest.prototype.testAddToCache = function() {
- var service = new osapi.container.Service();
+ var service = new osapi.container.Service(new osapi.container.Container());
this.setupUtilCurrentTimeMs(120);
var cache = {};
Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandler.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandler.java?rev=1231211&r1=1231210&r2=1231211&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandler.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandler.java Fri Jan 13 17:59:32 2012
@@ -18,12 +18,19 @@
*/
package org.apache.shindig.gadgets.servlet;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.inject.Inject;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletionService;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.ExecutorService;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.servlet.http.HttpServletResponse;
import org.apache.shindig.common.uri.Uri;
import org.apache.shindig.common.uri.Uri.UriException;
@@ -40,20 +47,12 @@ import org.apache.shindig.protocol.Servi
import org.apache.shindig.protocol.conversion.BeanDelegator;
import org.apache.shindig.protocol.conversion.BeanFilter;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CompletionService;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorCompletionService;
-import java.util.concurrent.ExecutorService;
-
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.servlet.http.HttpServletResponse;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Inject;
/**
* Provides endpoints for gadget metadata lookup and more.
@@ -129,7 +128,8 @@ public class GadgetsHandler {
protected final BeanDelegator beanDelegator;
@Inject
- public GadgetsHandler(ExecutorService executor, GadgetsHandlerService handlerService,
+ public GadgetsHandler(ExecutorService executor,
+ GadgetsHandlerService handlerService,
BeanFilter beanFilter) {
this.executor = executor;
this.handlerService = handlerService;
@@ -317,7 +317,7 @@ public class GadgetsHandler {
protected Callable<CallableData> createTokenJob(final String url,
BaseRequestItem request) throws ProcessingException {
// TODO: Get token duration from requests
- final TokenRequestData tokenRequest = new TokenRequestData(url, request, null);
+ final TokenRequestData tokenRequest = new TokenRequestData(url, request);
return new Callable<CallableData>() {
public CallableData call() throws Exception {
try {
@@ -563,15 +563,27 @@ public class GadgetsHandler {
protected class TokenRequestData extends AbstractRequest
implements GadgetsHandlerApi.TokenRequest {
- public TokenRequestData(String url, BaseRequestItem request, Long durationSeconds)
+ private Long moduleId;
+
+ public TokenRequestData(String url, BaseRequestItem request)
throws ProcessingException {
super(url, request, DEFAULT_TOKEN_FIELDS);
+
+ // The moduleId for the gadget (if it exists) is the fragment of the URI:
+ // ex: http://example.com/gadget.xml#1 or http://example.com/gadget.xml
+ // zero is implied if missing.
+ String moduleId = this.uri.getFragmentParameter("moduleId");
+ this.moduleId = moduleId == null ? 0 : Long.valueOf(moduleId);
}
public GadgetsHandlerApi.AuthContext getAuthContext() {
return beanDelegator.createDelegator(
request.getToken(), GadgetsHandlerApi.AuthContext.class);
}
+
+ public Long getModuleId() {
+ return moduleId;
+ }
}
@VisibleForTesting
Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerApi.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerApi.java?rev=1231211&r1=1231210&r2=1231211&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerApi.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerApi.java Fri Jan 13 17:59:32 2012
@@ -23,6 +23,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import org.apache.shindig.auth.SecurityToken;
import org.apache.shindig.common.uri.Uri;
import org.apache.shindig.protocol.conversion.BeanFilter.Unfiltered;
@@ -198,12 +199,13 @@ public class GadgetsHandlerApi {
public interface TokenRequest extends BaseRequest {
public AuthContext getAuthContext();
- // TODO: Consider support container controlled token duration
- // public Long getDurationSeconds();
+ public Long getModuleId();
}
public interface TokenResponse extends BaseResponse {
public String getToken();
+ public Integer getTokenTTL();
+ public Long getModuleId();
}
// TODO(jasvir): Support getRefresh and noCache
Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java?rev=1231211&r1=1231210&r2=1231211&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java Fri Jan 13 17:59:32 2012
@@ -55,6 +55,7 @@ import org.apache.shindig.gadgets.js.JsS
import org.apache.shindig.gadgets.process.ProcessingException;
import org.apache.shindig.gadgets.process.Processor;
import org.apache.shindig.gadgets.servlet.CajaContentRewriter.CajoledResult;
+import org.apache.shindig.gadgets.servlet.GadgetsHandlerApi.AuthContext;
import org.apache.shindig.gadgets.spec.Feature;
import org.apache.shindig.gadgets.spec.GadgetSpec;
import org.apache.shindig.gadgets.spec.LinkSpec;
@@ -152,6 +153,7 @@ public class GadgetsHandlerService {
protected final CajaContentRewriter cajaContentRewriter;
protected final GadgetAdminStore gadgetAdminStore;
protected final FeatureRegistryProvider featureRegistryProvider;
+ protected final ModuleIdManager moduleIdManager;
@Inject
public GadgetsHandlerService(TimeSource timeSource, Processor processor,
@@ -161,7 +163,8 @@ public class GadgetsHandlerService {
@Named("shindig.cache.xml.refreshInterval") long specRefreshInterval,
BeanFilter beanFilter, CajaContentRewriter cajaContentRewriter,
GadgetAdminStore gadgetAdminStore,
- FeatureRegistryProvider featureRegistryProvider) {
+ FeatureRegistryProvider featureRegistryProvider,
+ ModuleIdManager moduleIdManager) {
this.timeSource = timeSource;
this.processor = processor;
this.iframeUriManager = iframeUriManager;
@@ -176,6 +179,7 @@ public class GadgetsHandlerService {
this.cajaContentRewriter = cajaContentRewriter;
this.gadgetAdminStore = gadgetAdminStore;
this.featureRegistryProvider = featureRegistryProvider;
+ this.moduleIdManager = moduleIdManager;
this.beanDelegator = new BeanDelegator(API_CLASSES, ENUM_CONVERSION_MAP);
}
@@ -265,12 +269,36 @@ public class GadgetsHandlerService {
throws SecurityTokenException, ProcessingException {
verifyBaseParams(request, true);
Set<String> fields = beanFilter.processBeanFields(request.getFields());
+ AuthContext authContext = request.getAuthContext();
+
+ SecurityToken tokenData = null;
+ String token = null;
+
+ Long moduleId = request.getModuleId();
+ if (moduleId == null) {
+ // Zero means there's no persisted module instance and the container doesn't care to persist it.
+ moduleId = 0L;
+ } else if (moduleId < 0) {
+ // Please generate a module Id for me
+ moduleId = moduleIdManager.generate(request.getUrl(), authContext);
+ }
+ if (moduleId > 0) {
+ moduleId = moduleIdManager.validate(request.getUrl(), authContext, moduleId);
+ }
+
+ if (moduleId != null) {
+ tokenData = convertAuthContext(authContext, request.getContainer(),
+ request.getUrl().toString(), moduleId);
+ token = securityTokenCodec.encodeToken(tokenData);
+ }
- SecurityToken tokenData = convertAuthContext(request.getAuthContext(), request.getContainer(),
- request.getUrl().toString());
- String token = securityTokenCodec.encodeToken(tokenData);
Long expiryTimeMs = tokenData == null ? null : tokenData.getExpiresAt();
- return createTokenResponse(request.getUrl(), token, fields, expiryTimeMs);
+
+ Integer tokenTTL = isFieldIncluded(fields, "tokenTTL") ?
+ securityTokenCodec.getTokenTimeToLive() : null;
+ moduleId = isFieldIncluded(fields, "moduleId") ? moduleId : null;
+
+ return createTokenResponse(request.getUrl(), token, fields, expiryTimeMs, tokenTTL, moduleId);
}
public GadgetsHandlerApi.JsResponse getJs(GadgetsHandlerApi.JsRequest request)
@@ -495,13 +523,18 @@ public class GadgetsHandlerService {
}
private SecurityToken convertAuthContext(GadgetsHandlerApi.AuthContext authContext,
- String container, String url) {
+ String container, String url) {
+ return convertAuthContext(authContext, container, url, 0);
+ }
+
+ private SecurityToken convertAuthContext(GadgetsHandlerApi.AuthContext authContext,
+ String container, String url, long moduleId) {
if (authContext == null) {
return null;
}
return beanDelegator.createDelegator(authContext, SecurityToken.class,
ImmutableMap.<String, Object>of("container", container,
- "appid", url, "appurl", url));
+ "appid", url, "appurl", url, "moduleId", moduleId));
}
public GadgetsHandlerApi.BaseResponse createErrorResponse(
@@ -545,16 +578,21 @@ public class GadgetsHandlerService {
@VisibleForTesting
GadgetsHandlerApi.TokenResponse createTokenResponse(
- Uri url, String token, Set<String> fields, Long tokenExpire) {
+ Uri url, String token, Set<String> fields, Long tokenExpire, Integer tokenTTL, Long moduleId) {
return (GadgetsHandlerApi.TokenResponse) beanFilter.createFilteredBean(
beanDelegator.createDelegator(null, GadgetsHandlerApi.TokenResponse.class,
- ImmutableMap.<String, Object>of(
- "url", url,
- "error", BeanDelegator.NULL,
- "token", BeanDelegator.nullable(token),
- "responsetimems", timeSource.currentTimeMillis(),
- "expiretimems", BeanDelegator.nullable(tokenExpire))),
- fields);
+ ImmutableMap.<String, Object>builder()
+ .put("url", url)
+ .put("error", BeanDelegator.NULL)
+ .put("token", BeanDelegator.nullable(token))
+ .put("responsetimems", timeSource.currentTimeMillis())
+ .put("expiretimems", BeanDelegator.nullable(tokenExpire))
+ .put("tokenttl", BeanDelegator.nullable(tokenTTL))
+ .put("moduleid", BeanDelegator.nullable(moduleId))
+ .build()
+ ),
+ fields
+ );
}
protected JsUri createJsUri(GadgetsHandlerApi.JsRequest request) {
Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleIdManager.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleIdManager.java?rev=1231211&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleIdManager.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleIdManager.java Fri Jan 13 17:59:32 2012
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.servlet;
+
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.servlet.GadgetsHandlerApi.AuthContext;
+
+import com.google.inject.ImplementedBy;
+
+@ImplementedBy (ModuleIdManagerImpl.class)
+public interface ModuleIdManager {
+ /**
+ * Checks to make sure that the proposed moduleId for this gadget is valid.
+ * This data is not 100% trustworthy becaue we can't extract it from a
+ * token, so we validate it here, usually against the AuthContext viewerId,
+ * gadgetUrl, moduleId combination.
+ *
+ * If the moduleId is invalid the implementation may return:
+ * null (in which case a null security token will be returned to the container)
+ * 0 (Default value for non-persisted gadgets)
+ * A newly generated moduleId
+ *
+ * If the supplied moduleId is valid, this function is expected to return the
+ * value of the moduleId param.
+ *
+ * @param gadgetUri The location of the gadget xml to validate the token for
+ * @param containerAuthContext The Auth context. Basically, the container security token.
+ * @param moduleId The moduleId sent by the container page.
+ * @return moduleId.
+ */
+ public Long validate(Uri gadgetUri, AuthContext containerAuthContext, Long moduleId);
+
+ /**
+ * Generate and persist a new moduleId for the given gadgetUri and container auth context.
+ *
+ * @param gadgetUri The location of the gadget xml to generate the token for
+ * @param containerAuthContext The Auth context. Basically, the container security token.
+ * @return moduleId.
+ */
+ public Long generate(Uri gadgetUri, AuthContext containerAuthContext);
+}
\ No newline at end of file
Propchange: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleIdManager.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleIdManagerImpl.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleIdManagerImpl.java?rev=1231211&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleIdManagerImpl.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleIdManagerImpl.java Fri Jan 13 17:59:32 2012
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.servlet;
+
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.servlet.GadgetsHandlerApi.AuthContext;
+
+/**
+ * Override this class to provide meaningful moduleId validation and generation for gadgets.
+ */
+public class ModuleIdManagerImpl implements ModuleIdManager {
+ public Long validate(Uri gadgetUri, AuthContext containerAuthContext, Long moduleId) {
+ return 0L;
+ }
+
+ public Long generate(Uri gadgetUri, AuthContext containerAuthContext) {
+ return 0L;
+ }
+}
+
Propchange: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ModuleIdManagerImpl.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerServiceTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerServiceTest.java?rev=1231211&r1=1231210&r2=1231211&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerServiceTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerServiceTest.java Fri Jan 13 17:59:32 2012
@@ -129,11 +129,11 @@ public class GadgetsHandlerServiceTest e
gadgetHandler = new GadgetsHandlerService(timeSource, processor, urlGenerator, tokenCodec,
proxyUriManager, jsUriManager, proxyHandler, jsPipeline, jsRequestBuilder,
SPEC_REFRESH_INTERVAL_MS, new BeanFilter(), cajaContentRewriter, gadgetAdminStore,
- featureRegistryProvider);
+ featureRegistryProvider, new ModuleIdManagerImpl());
gadgetHandlerWithAdmin = new GadgetsHandlerService(timeSource, processor, urlGenerator,
tokenCodec, proxyUriManager, jsUriManager, proxyHandler, jsPipeline, jsRequestBuilder,
SPEC_REFRESH_INTERVAL_MS, new BeanFilter(), cajaContentRewriter, gadgetAdminStore,
- featureRegistryProvider);
+ featureRegistryProvider, new ModuleIdManagerImpl());
}
// Next test verify that the API data classes are configured correctly.
Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java?rev=1231211&r1=1231210&r2=1231211&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java Fri Jan 13 17:59:32 2012
@@ -138,7 +138,7 @@ public class GadgetsHandlerTest extends
GadgetsHandlerService service = new GadgetsHandlerService(timeSource, processor, urlGenerator,
codec, proxyUriManager, jsUriManager, proxyHandler, jsPipeline, jsRequestBuilder,
SPEC_REFRESH_INTERVAL, beanFilter, cajaContentRewriter, gadgetAdminStore,
- featureRegistryProvider);
+ featureRegistryProvider, new ModuleIdManagerImpl());
GadgetsHandler handler = new GadgetsHandler(new ImmediateExecutorService(), service, beanFilter);
registry = new DefaultHandlerRegistry(injector, converter,
new HandlerExecutionListener.NoOpHandler());