Core-Gadget - PubSub

   <section title="Inter-Gadget Eventing" anchor="interGadgetEventing">
 
    <t>The inter-gadget eventing feature, common known as "pub/sub", provides
    for loosely-coupled and asynchronous inter-gadget communication based
    on the <eref target="http://www.openajax.org/member/wiki/OpenAjax_Hub_2.0_Specification_Introduction">
    OpenAjax Hub 2.0</eref> specification.</t>
 
    <t>The "pub/sub" feature provides:
      <list style="symbols">
        <t>An event hub, provided by the container and fully compliant 
        with OpenAjax Hub 2.0, that manages the subscription and publication 
        of events,</t>
        <t>Methods for publishing and subscribing to events, and </t>
        <t>Mechanisms for declaratively specifying metadata within
        a gadget's XML definition relevant to publishing and subscribing 
        to events.</t>
      </list>
    </t>
 
    <t>The process is straightforward:
      <list style="symbols">
        <t>First, a container that supports the "pub/sub" feature needs to 
        initialize the Hub and all default settings.</t>
        <t>Second, a container can bootstrap and simplify the connection of 
        a gadget to the hub by registering an onLoad handler using the 
        gadgets.util.registerOnLoadHandler API. </t>
        <t>Third, once the Hub is initialized by the container, individual gadget's
        that declare support for the "pubsub-2" feature using either the 
        "Optional" or "Required" tag within the Gadget specifications 
        "ModulePrefs" can use the provided JavaScript APIs to publish 
        events to the hub using "topics", or use the JavaScript APIs to
        subscribe to "topics" published by the Hub. When a gadget publishes
        and event to the Hub using a specific topic, all gadget's connected 
        to that Hub and subscribed to the same topic will receive a copy 
        of the event.</t>
      </list>
    </t>
 
    <t>A "topic" is a String value that conforms to the OpenAjax Hub 2.0 
    specification's <eref target="http://www.openajax.org/member/wiki/OpenAjax_Hub_2.0_Specification_Topic_Names">Topic Name Rules</eref>.
    All topic names prefixed with "org.opensocial." are reserved for use by
    the OpenSocial specification. Developers MUST NOT use the "org.opensocial."
    prefix when defining their own topics.</t>
 
    <section title="Initializing the Hub within the Container" anchor="ContainerExample">
 
      <t>The following example illustrates a non-normative example how a 
      container could provide support for this feature.</t>
 
      <list style="numbers">
        <t>Set default values:
          <artwork type="code">
// Create a pubsub settings object
gadgets.HubSettings = {};
 
// Set default HubClient constructor params object
gadgets.HubSettings.params = {
 HubClient: {
    onSecurityAlert: function( alertSource, alertType ) {
      alert( "Gadget stopped attempted security breach: " + alertType );
      window.location.href = "about:blank"; // Forces container to see Frame Phish alert and probably close this gadget
    },
    scope: gadgetInstance
  } };
 
// Set default onComplete function for HubClient.connect
gadgets.HubSettings.onConnected = function( hub, suc, err ) { };
            </artwork>
        </t>
        <t>
    Register an onLoad handler
    <t>An onLoad handler to actually create the HubClient and connect it
        to the ManagedHub. Delaying the HubClient creation and
        connection allows the gadget to override default values stored
        in gadgets.HubSettings. For example, IframeHubClient
        supports params properties such as seed, tokenLength and log,
        which are not set by default; and a gadget might need to
        override onSecurityAlert and/or scope, for which default values
        are provided. More importantly, the onComplete function for
        HubClient.connect usually sets up the gadget's subscriptions by
        calling gadgets.Hub.subscribe, or if the connection fails
        asynchronously, the onComplete function handles the error.</t>
            <artwork type="code">
// Register an onLoad handler
gadgets.util.registerOnLoadHandler( function() {
  try {
    // Create the HubClient.
    gadgets.Hub = new OpenAjax.hub.IframeHubClient(  gadgets.HubSettings.params );
 
    // Connect to the ManagedHub
    gadgets.Hub.connect( gadgets.HubSettings.onConnect );
 
  } catch(e) {
    // TODO: error handling should be consistent with other OS gadget initialization error handling
  }
} );
            </artwork>
        </t>
      </list>
    </section>
 
    <section title="Gadget Examples" anchor="GadgetExample">
 
      <t>The following illustrates a non-normative example of a gadget that 
      subscribes to a topic published by the Hub.</t>
 
      <t>Note that, by default, all of the necessary defaults parameters
      on the underlying HubClient connected for the gadget were initialized
      when the gadget was loaded. If the gadget developer wishes to override the 
      default parameters to the HubClient constructor, it can do so by 
      setting values on gadgets.HubSettings as illustrated in the example.</t>
 
      <figure><artwork type="code">
  &lt;Module&gt;
    &lt;ModulePrefs title="Sample PubSub Subscriber" height="250"&gt;
      &lt;Require feature="pubsub-2"&gt;
        &lt;Param name="topics"&gt;&lt;![CDATA[ 
          &lt;Topic title="Random Number" 
            name="org.apache.shindig.random-number"
            description="Subscribes to random number generator." 
            type="number"
            subscribe="true"/&gt;
          ]]&gt;&lt;/Param&gt;
      &lt;/Require&gt;
    &lt;/ModulePrefs&gt;
    &lt;Content type="html"&gt;&lt;![CDATA[
      &lt;script&gt;
var subId;
 
// Example of setting a parameter to the HubClient used by pubsub-2 feature.
gadgets.HubSettings.params.HubClient.onSecurityAlert = function(alertSource, alertType) {
  alert("SECURITY ERROR!");
  window.location.href = "about:blank";
};
 
function callback(topic, data, subscriberData) {
  document.getElementById("output").innerHTML =
    "message : " + gadgets.util.escapeString(data + "") + "&lt;br/&gt;" +
    "received at: " + (new Date()).toString();
}
 
function subscribe() {
  subId = gadgets.Hub.subscribe("org.apache.shindig.random-number", callback);
}
 
function unsubscribe() {
  gadgets.Hub.unsubscribe(subId);
  document.getElementById("output").innerHTML = "";
}
      &lt;/script&gt;
      &lt;div&gt;
        &lt;input type="button" value="Subscribe" onclick="subscribe()"/&gt;
        &lt;input type="button" value="Unsubscribe" onclick="unsubscribe()"/&gt;
      &lt;/div&gt;
      &lt;div id="output"&gt;&lt;/div&gt;
    ]]>&lt;/Content&gt;
  &lt;/Module&gt;
   </artwork></figure>
 
     <t>Similarly, below is a non-normative example of a gadget that 
     publishes events to the Hub:</t>
 
     <figure><artwork>
  &lt;Module&gt;
    &lt;ModulePrefs title="Sample PubSub Publisher" height="250"&gt;
      &lt;Require feature="pubsub-2"&gt;
        &lt;Param name="topics"&gt;
          &lt;![CDATA[ 
            &lt;Topic title="Random Number" 
              name="org.apache.shindig.random-number"
              description="Publishes a random number." 
              type="number"
              publish="true" /&gt;
        ]]>&lt;/Param&gt;
      &lt;/Require&gt;
    &lt;/ModulePrefs&gt;
    &lt;Content type="html"&gt;&lt;![CDATA[
      &lt;script&gt;
function publish() {
  var message = Math.random();
  gadgets.Hub.publish("org.apache.shindig.random-number", message);
  document.getElementById("output").innerHTML = message;
}
      &lt;/script&gt;
      &lt;div&gt;
        &lt;input type="button" value="Publish a random number" onclick="publish()"/&gt;
      &lt;/div&gt;
      &lt;div id="output">&lt;/div&gt;
    ]]>&lt;/Content&gt;
  &lt;/Module&gt;
     </artwork></figure>
 
    </section>
 
    <section title="gadgets.Hub" anchor="gadgets.Hub">
      <section title="Method Details">
        <section title="publish" anchor="publish">
          <t>publish(topic, payload)</t>
          <t>Description: The publish method conforms to the semantics of the
          OA Hub. The OAHub embraces the notion that pubsub is anonymous and
          does not automatically include any information about the
          identification of the publishing gadget with the message. The
          following is an excerpt from their documentation.</t>
          <t>Parameters:
            <texttable align="left">
              <ttcol>Name</ttcol>
              <ttcol>Type</ttcol>
              <ttcol>Description</ttcol>
              <c>topic</c>
              <c>String</c>
              <c>A string that conforms to the rules defined above and by the
              OA Hub to name the channel that the payload will be deliverd on.
              Wildcards are NOT permitted.</c>
              <c>payload</c>
              <c>*</c>
              <c>It is permissible to publish any object. The payload MUST
              be serializable to JSON.</c>
            </texttable>
          </t>
          <t>See the <eref target="http://www.openajax.org/member/wiki/OpenAjax_Hub_2.0_Specification_Managed_Hub_APIs#OpenAjax.hub.Hub.prototype.publish">OpenAjax Hub 2.0 documentation</eref> for more information.</t>
          <section title="subscribe" anchor="subscribe">
            <t>subscribe(topic, callback [,scope [,onCompleteCallback [,subscriberData]]])</t>
            <t>Description: The subscribe method is used to indicate to the
            hub the topic from which the gadget is interested in receiving
            information. When information is published on the topic, the hub
            will invoke the callback method on the gadget. Since a gadget may
            have multiple subscriptions on the same topic, the subscribe
            method returns an opaque identifier that is used to uniquely
            identify the subscription. This identifier is used to unsubscribe
            to the topic. It is gadget developer's responsibility to manage
            this identifier.</t>
            <t>Parameters:
              <texttable align="left">
                <ttcol>Name</ttcol>
                <ttcol>Type</ttcol>
                <ttcol>Description</ttcol>
                <c>topic</c>
                <c>String</c>
                <c>A string that conforms to the rules defined above and by the OA Hub
                to name the channel that the payload will be deliverd on. Wildcards
                MAY be used.</c>
                <c>callback</c>
                <c>String</c>
                <c>A callback function to be executed when the tab is selected. The
                callback function will not be called until after the existing
                callstack has completed execution.</c>
                <c>scope</c>
                <c>object</c>
                <c>When onData callback or onComplete callback is invoked, the
                JavaScript "this" keyword refers to this scope object. If no scope is
                provided, default is window.</c>
                <c>onCompleteCallback</c>
                <c>function</c>
                <c>Function invoked to tell the client application whether the
                subscribe operation succeeded or failed.</c>
                <c>subscriberData</c>
                <c>*</c>
                <c>Client application provides this data, which is handed back to the
                client application in the subscriberData parameter of the onData
                callback function.</c>
              </texttable>
            </t>
            <t>Returns:
              <texttable align="left">
                <ttcol>Type</ttcol>
                <ttcol>Description</ttcol>
                <c>String</c>
                <c>An opaque subscription identifier. This identifier is an arbitrary
                ID string that is unique within this Hub instance</c>
              </texttable>
            </t>
            <t>See the <eref target="http://www.openajax.org/member/wiki/OpenAjax_Hub_2.0_Specification_Managed_Hub_APIs#OpenAjax.hub.Hub.prototype.subscribe">OpenAjax Hub documentation</eref> for
            more information</t>
          </section>
          <section title="unsubscribe" anchor="unsubscribe">
            <t>unsubscribe(subscriptionId)</t>
            <t>Description: This method is used to remove a subuscription for a
            gadget from the hub. The unsubscribe function immediately throws an
            exception if there is no subscription with the specified subscription
            ID. Otherwise, unsubscribe immediately deactivates the subscription.
            </t>
            <t>Parameters:
              <texttable align="left">
                <ttcol>Name</ttcol>
                <ttcol>Type</ttcol>
                <ttcol>Description</ttcol>
                <c>subscriptionId</c>
                <c>String</c>
                <c>The subscriptionId is the opaque string that is returned from the
                    subscribe(...) method.</c>
              </texttable>
            </t>
            <t>See the <eref target="http://www.openajax.org/member/wiki/OpenAjax_Hub_2.0_Specification_Managed_Hub_APIs#OpenAjax.hub.Hub.prototype.unsubscribe">OpenAjax Hub documentation</eref> for
            more information.</t>
          </section>
        </section>
        <section title="Other Methods" anchor="OtherMethods">
          <t>The 'gadgets.Hub' object is an instance of IframeHubClient and supports some additional methods.
          Please see the <eref target="http://www.openajax.org/member/wiki/OpenAjax_Hub_2.0_Specification_Managed_Hub_APIs#OpenAjax.hub.IframeHubClient">OpenAjax Hub documentation</eref> for more information.</t>
        </section>
      </section>
    </section>
 
    <section title="Wiring Metadata">
 
      <t>As illustrated by the previous example gadgets, the "pub/sub" feature 
      provides a means of allowing gadget developers to declaratively describe
      the topics their gadget's support directly within the feature declaration
      within the "ModulePrefs" element.</t>
 
      <figure><preamble>For example:</preamble>
      <artwork>
  &lt;Module&gt;
    &lt;ModulePrefs title="Sample PubSub Publisher" height="250"&gt;
      &lt;Require feature="pubsub-2"&gt;
        &lt;Param name="topics"&gt;
          &lt;![CDATA[ 
            &lt;Topic title="Random Number" 
              name="org.apache.shindig.random-number"
              description="Publishes a random number." 
              type="number"
              publish="true" /&gt;
        ]]>&lt;/Param&gt;
      &lt;/Require&gt;
    &lt;/ModulePrefs&gt;
    ...
  &lt;/Module&gt;
      </artwork></figure>
 
      <t>When gadgets use the &lt;Topic&gt; element, containers are able
      to "wire" gadgets together either automatically or via a user interface
      that allows a user to connect gadgets that publish events to a given
      topic to gadgets that subscribe to those events.</t>
 
      <t>The &lt;Topic&gt; element has the following attributes:</t>
      <texttable align="left">
          <ttcol>Attribute</ttcol>
          <ttcol>Type</ttcol>
          <ttcol>Usage</ttcol>
          <ttcol>Description</ttcol>
          <c>name</c>
          <c>String</c>
          <c>Required</c>
          <c>
          The dot-delimited topic name, e.g. "org.example.randomNumber". This
          name follows the rules defined in the <eref target="http://www.openajax.org/member/wiki/OpenAjax_Metadata_1.0_Specification_Widget_Metadata#topic_element_name_attribute">OpenAjax Widget Metadata
          specification</eref>. Developers of gadgets MAY allow the @name attribute to be ovveridden using user preference variables. See <xref target="usingVariablesForNameAttribute">Using Varuables for @name</xref></c>
 
          <c>type</c>
          <c>String</c>
          <c>Optional</c>
          <c>Type name for the event's payload data. When not specificed, any
          type wil be allowed. See <xref target="EventDataTypes">Event Data Types</xref>.</c>
 
          <c>title</c>
          <c>String</c>
          <c>Optional</c>
          <c>Title for this type of event that is appropriate for a non-technical reader. When not specified, the value of the "name" attribute will be used.</c>
 
          <c>publish</c>
          <c>boolean</c>
          <c>Optional</c>
          <c>Indicates if the gadget publishes events on this topic. The default value is "false".</c>
 
          <c>subscribe</c>
          <c>boolean</c>
          <c>Optional</c>
          <c>Indicates if the gadget subscribes to events that are published on this topic. The default value is "false".</c>
 
          <c>description</c>
          <c>String</c>
          <c>Optional</c>
          <c>
          The textual description of the gadget's publish or subscribe
          endpoint.
          This can be used as an indication of the gadget's behavior.
          Consider a gadget that subscribes to a topic "com.example.address".
          The description migh read, "When this gadget receives an event on the com.example.address
          topic, it displays mass transit options within 10km of the address received as the event payload."</c>
 
          <c>aboutUrl</c>
          <c>String</c>
          <c>Optional</c>
          <c>
          A URL pointing to a resource that provides more extensive
          descriptive information than can be provided in the description
          attribute.</c>
      </texttable>
 
      <section title="Using Variables for @name" anchor="usingVariablesForNameAttribute">
        <t>In the absence of a specific standard for events within a given
        domain, it is inevitable that different groups of developers,
        working in different niches on similar problems, will use different
        topic naming schemes for what is essentially the same event. While
        some developers in a domain may eventually consolidate around a
        standard set of topic names, it's also inevitable that installed
        bases, legacy implementations, politics, requirement to integrate
        with third party gadgets from other domains, schedule constraints
        and other factors will ensure that once a topic space becomes
        balkanized, it will remain that way for a long time.</t>
        <t>It is important that the specification offer a mechanism that allows
        developers to bridge simple mismatches between gadgets. It is
        important that gadget developers use this mechanism where possible.
        This will maximize the reusability of gadgets -- a major goal.</t>
 
        <figure><preamble>The following is an example showing the use of 
        variable substituion in the definition of the @name attribute.</preamble>
        <artwork xml:space="preserve">
  &lt;Require feature="pubsub-2"&gt;
    &lt;Param name="topics"&gt;&lt;![CDATA[
       &lt;Topic title="Selected Location" name="__UP_location__"
             description="The currently selected location" type="http://nsgs.gov/geo#Place"
             publish="false" subscribe="true" aboutUrl="http://nsgs.gov"&gt;
      &lt;/Topic&gt;
      &lt;!-- etc. for other topics --&gt;
    ]]&gt;&lt;/Param&gt;
  &lt;/Require&gt;
         </artwork></figure>
      </section>
 
      <section title="Event Data Types" anchor="EventDataTypes">
        <t>The OpenAjax Hub has a predefined set of identifiers that are used 
        to indicate the data type. Tooling and runtime container code can use 
        this to infer information about the messages being published
        as well as the parameters a gadget expects to receive when it
        subscribes to a topic.</t>
        <t>The data types provided by the OpenAjax Hub are "built in". These
        are referred to as the OpenAjax common types, and they require no
        namespace qualifier. When a type other than an OpenAjax common type
        is used, it MUST contain a namesake qualifier. The namespace should
        conform to reverse DNS rules. The namespace org.opensocial.* MUST NOT be
        used and is reserved for types defined by this specification, 
        e.g. social data types.</t>
 
        <texttable align="left">
          <ttcol>Type Name</ttcol>
          <ttcol>Comments</ttcol>
          <c>string</c>
          <c>ECMAScipt string</c>
          <c>number</c>
          <c>ECMAScipt number </c>
          <c>boolean</c>
          <c>ECMAScipt boolean </c>
          <c>array</c>
          <c>ECMAScipt array, e.g. [ 1, 1, 2, 3, 5, 8 ]. The element type/s are not specified when the generic "array" type is used.</c>
          <c>object *</c>
          <c>ECMAScipt object, e.g. { foo: "bar", baz: "boo" }. The specifics of the object are not specified when the generic "object" type is used.</c>
          <c>null *</c>
          <c>ECMAScipt null</c>
          <c>length *</c>
          <c>Any CSS length value <span style="color:red"> Howard 2009.11.10: CSS version?</span></c>
          <c>color *</c>
          <c>Any CSS color value</c>
          <c>id</c>
          <c>ID value - probably not useful for OpenSocial Gadgets, but might as well keep the two specs in sync</c>
          <c>class *</c>
          <c>zero of more CSS class names, separated by spaces</c>
          <c>style *</c>
          <c>a string that could be used as value for a 'style' attribute</c>
          <c>url</c>
          <c>A URL <span style="color:red"> Howard 2009.11.09: Do we want "uri" also?</span></c>
          <c>html</c>
          <c>A fragment of HTML markup.</c>
          <c>countrycode *</c>
          <c>A string that represents an [http://www.iso.org/iso/country_codes/iso_3166_code_lists.htm A3 ISO 3166 country code].</c>
          <c>languagecode *</c>
          <c>A string that represents an [http://www.loc.gov/standards/iso639-2/php/code_list.php ISO 639-2 language code].</c>
          <c>email</c>
          <c>A string that represents an e-mail address.</c>
          <c>person</c>
          <c>A string that holds a person's name.</c>
          <c>postalcode</c>
          <c>A string that represents a postal code.</c>
          <c>phone</c>
          <c>A string that represents a phone number.</c>
          <c>date *</c>
          <c>A string that represents a date. MUST be expressed using the "Date Time String Format" defined in the [http://www.ecmascript.org/docs/tc39-2009-043.pdf ECMAScript5 specification] using one of the date-only forms. For example: "2009-12-15"</c>
          <c>time *</c>
          <c>A string that represents a time of day. MUST be expressed using the "Date Time String Format" defined in the [http://www.ecmascript.org/docs/tc39-2009-043.pdf ECMAScript5 specification] using one of the time-only forms. For example: "18:45:00Z" or "10:26:24-05:00"</c>
          <c>timestamp *</c>
          <c>A string that represents a date and time of day. MUST be expressed using the "Date Time String Format" defined in the [http://www.ecmascript.org/docs/tc39-2009-043.pdf ECMAScript5 specification]. For example: "2009-12-15:18:45.000Z"</c>
          <c>duration *</c>
          <c>A string that represents a duration. MUST have format "PYYYY-DDDThh:mm:ss.fff". For example, "P0400-152T20:45:33.123" means "400 years, 152 days, 20 hours, 45 minutes, 33.123 seconds, while "P0003-000T01:56:22.000" means "3 years, 1 hour, 56 minutes and 22.000 seconds." (Must use this one variant defined in the ISO 8601 standard). </c>
          <c>*</c>
          <c>Asterisk, or missing type attribute, means "any datatype"</c>
        </texttable>
      </section>
    </section>
  </section>