OpenAjax Hub 1.1 Proposed APIs

From MemberWiki

Jump to: navigation, search

Contents

Introduction

This wiki page holds early work-in-progress on how the APIs for OpenAjax Hub 1.1 might look. The APIs reflected in this wiki page support backwards compatibility with OpenAjax Hub 1.0 and attempt to follow the spirit of the OpenAjax Hub 1.1 Roadmap [1]. We are writing the specifications and developing an open source reference implementation in parallel within the OpenAjax open source project at SourceForge [2].


Note:

  • [TBD] ...issue .. [/TBD] are issues which need to be resolved
  • comments are inserted as [initials] ...comment ... [/initials]
  • [rationale][/rationale] discusses some design decisions made.


Overview

Some general points to aid in understanding the API:

  • Specificity of API to client-side messaging:
    • The API is not meant to be specific to client-side messaging. However, it has been written with client-side intra-frame and cross-frame messaging in mind. That bias probably needs to be corrected.
    • Code derived from SMash is expected to be the default provider for cross-frame messaging in the reference implementation of Hub 1.1. The provider specific extensions for the default provider are in a separate section.
  • Demultiplexing and Provider SPI:
    • Messaging can be implemented by multiple providers. There are separate providers for the intra-frame and cross-frame messaging pattern, and potentially multiple providers for each messaging pattern. We assume that all providers implement all API methods OpenAjax.hub.<method> (documented in the next section) by <providerObject>.<method>. Additional SPI only functionality is described in a separate section.
    • The APIs prefixed by openajax.hub will be directly implemented by a shim, that based on some parameter value (e.g. host, connHandle.getHost(), subHandle.getConnHandle().getHost() etc.) will demultiplex the method invocation to the appropriate provider.
  • Comparison with OAA Hub 1.1 roadmap document: The API is inspired by the roadmap [3], and therefore has significant similarity with it. Some important differences are noted below:
    • The roadmap defines a hierarchy using host, room and topic, where a host contains multiple rooms, and a room contains multiple topics. The host is null for local messaging, and room is the abstraction on which an administrative policy can be applied (using manageRoom). We eliminate the room abstraction, and do administration at the host, to reduce the number of concepts in this hierarchy (since topics are anyway hierarchical).
    • The roadmap uses secret numbers returned in the connect and join methods to do some level of authentication. They have been dropped, and authentication is handled internally by the hub.
  • Comparison with Hub 1.0:
    • The API is asynchronous, to accomodate the asynchrony of cross-frame messaging.
    • There is a need to authenticate publishers and subscribers (jointly referred to as clients), and based on that perform some authorization on their actions. In naming the clients we adopt an approach similar to the WHATWG HTML 5 proposal [4], using the domain and URI of the client.
    • The data passed on publish is a pure data Object (no functions). Many cross-frame mechanisms will serialize and deserialize the data as JSON and cannot be expected to handle functions. Furthermore, even mechanisms which allow function passing face a number of subtle security issues around getter and setter functions.
    • The data passed on publish is pass-by-value, not pass-by-reference. Again this is due to the serialization/deserialization performed by many cross-frame mechanisms. It also prevents any concurrency issues given the asynchronous nature of the transfer.
    • Absence of some syntactic features of Hub 1.0 in Hub 1.1: To avoid making the API too complex, we have not included the following syntactic features of Hub 1.0 in the Hub 1.1 API:
      • scope, subscriberData: Closures in JavaScript make these redundant.
      • filter: It is a JavaScript function that the subscriber could call itself in the callback method. Other publish/subscribe interfaces, like the Java Message Service (JMS), allow specification of a declarative (subset of SQL) filter, which the system can optimize the evaluation of (by aggregating multiple filters, or in a network setting move the filter closer to the source of the events/messages). Since the filter in Hub 1.0 is not a declarative specification, the usefulness seems limited (even for client-server messaging, like Comet).
  • Hub 1.1 Overview:
    • Terminology:
      • Hub-instance: The Openajax.hub object provides a way to access multiple different logical hubs, that may correspond to intra-frame messaging, cross-frame messaging and client-server messaging. We use the term logical hub-instance to refer to such a logical hub. Messages published at a logical hub-instance can potentially be received by any of its clients (subject to access control). That is, messages and topics have global scope within a logical hub-instance. However, messages will not automatically flow across two different logical hub-instances. Any message flow across logical hub-instances has to be coded by the application, such as by receiving a message on one logical hub-instance and then publishing it on another. For the remainder of this document, the term hub-instance refers to a logical hub-instance.
      • Client Roles: Each hub-instance has zero or more clients, and exactly one client that behaves in the role of a manager. The manager sees all the subscribe calls, and all the messages published at the hub-instance, and can impose any policy on allowing/disallowing subscriptions and publishers. The OpenAjax.hub.connect call connects a client to a hub-instance. Note that a hub-instance does not have one-to-one correspondence with a JavaScript object returned in OpenAjax.hub.connect, as different clients connecting to the same hub-instance will receive different JavaScript objects as return values.
    • Role selection: A role is selected in the OpenAjax.hub.connect call by specifying a string parameter, role, that is by default client and can be specified as manager.
    • Number of hub-instances for cross-frame messaging: The number of hub-instances for cross-frame messaging and how one specifies a particular hub-instance is left unspecified and dependent on the provider. Some possibilities are:
      • Exactly one hub-instance, where the manager is the top-level window object, and all its descendent iframes can be clients.
      • One hub-instance at each level of the iframe hierarchy, connecting a parent iframe (the manager), with its child iframes (the clients). The default provider will use this approach, with each iframe potentially talking to two hub-instances, one as the manager, and one as a client. The selection of the hub-instance will be done solely based on the role parameter provided in the OpenAjax.hub.connect call.
    • Topic access-control: The manage method provides a way to plugin general application-specific access-control policies by the manager, by registering callback functions for publish and subscribe actions. If no callback is registered for an action, all actions of that type will be denied.

Hub API

List of Functions

The OpenAjax Hub 1.1 provides the following APIs for its event management services.

  • OpenAjax.hub.configureProvider()
  • OpenAjax.hub.connect()

The connection handle object corresponding to a connection provides the following APIs.

  • manage()
  • subscribe()
  • unsubscribe()
  • publish()
  • disconnect()
  • reconnect()


Details

OpenAjax.hub.configureProvider({communicationType:string, providerName:string, providerConfig:object})

This method is used to give configuration parameters to a specific provider. It is not necessary to call this method if default configuration settings will be used for this provider.

Parameters

communicationType
The communicationType can be "cross-frame", "intra-frame", "server".
providerName
The providerName uniquely identifies the provider. [TBD] Need a robust naming approach such as using URIs, or reverse domain syntax. Borrow from OpenAjax.hub.registerLibrary? [/TBD]
providerConfig
The providerConfig is a data object to configure the provider. Top level property names in this object should be distinguished by provider name (e.g. "org.openajax.crossframe.default.<field>").

Return value

The return value is a boolean that is true if the provider was found and configured, else false.

OpenAjax.hub.connect({communicationType:string, [host:string], [role:string], callback:function, [providerName:string], [connectionConfig:object]})

Parameters

communicationType
The communicationType can be "cross-frame", "intra-frame", "server".
host (optional)
It is a URI string. It is not used for the "cross-frame" and "intra-frame" communication types.
role (optional)
The optional role is either "manager" or "client". The default value is "client".
callback
To accomodate asynchronous connects, in addition to the return value the callback function will be called with success or failure. The callback is defined as function(success:boolean, connHandle:object), where success is a boolean and connHandle is an object defined by the host. The callback may be invoked synchronously, just before returning from connect.
providerName (optional)
Explicitly specify the provider to be choosen. If not given, then the hub will choose a default provider among the available providers.
connectionConfig (optional)
Configures the provider for this connection. Top level property names in this object should be distinguished by provider name (e.g. "org.openajax.crossframe.default.<field>").

Return value

The return value is a connHandle object. It implements the main functions subscribe, manage, disconnect and reconnect described later as well as the following auxiliary functions:

  • The connHandle.isConnected() returns true iff the connection is established and active.
  • The connHandle.getHost() function returns the host.
  • The connHandle.equals() function returns true if two connection handles represent the same connection, else false.
  • The connHandle.getRole() function returns the role of referenced connection, i.e., either the string 'client' or 'manager'.
  • The connHandle.getManagerDomain() returns the domain of the manager.

[rationale] We use an opaque connHandle instead of a connId (used in the current Hub 1.1 roadmap) since it (1) makes the shim easier as it can dispatch method calls that specify a connHandle, but do not specify a host, without maintaining a mapping from connId to host, (2) handles can contain other handles, like the subHandle described later, so it makes the function signatures simpler. [/rationale]


connHandle.disconnect(callback:function)

Parameters

connHandle
The connHandle is the object provided in a previous connect.
callback
The callback is defined as function(success:boolean, connHandle:object). The connHandle object is equal to the one on which the disconnect method is invoked. The callback may be invoked synchronously, just before returning from connect.

Return value

The return value is a boolean indicating success or failure.

connHandle.reconnect(callback:function)

Parameters

connHandle
The connHandle is the object provided in a previous connect.
callback
The callback is defined as function(success:boolean, connHandle:object). The connHandle object is equal to the one on which the disconnect method is invoked. The callback may be invoked synchronously, just before returning from reconnect.

Return value

The return value is a boolean indicating success or failure.

Note

This function can also be used to abort an ongoing connection request.

connHandle.manage(pubCallback:function, subCallback:function)

Parameters

connHandle
The connHandle is the object provided in a previous connect in the "manager" role.
pubCallback
A callback to invoke on each publish call
subCallback
A callback to invoke on each subscribe call

If a null callback is registered, the corresponding operation is always denied.

  • pubCallback is defined as boolean function(topic:string, data:string, publisherInfo:{domain:string, uri:string}).
    • The topic does not contain any wild-cards (see Hub 1.0 spec).
    • The data represents the event payload. This allows for the policy to be dependent on the content of the event.
    • The publisherInfo is an object representing publishing client information. This has two string properties, domain and uri.
    • A return value of true represents that the publish operation is permitted, else it is not permitted.
  • subCallback is defined as boolean function(topic:string, subInfo:{domain:string, uri:string}).
    • The topic can contain wildcards (see Hub 1.0 spec).
    • The subInfo is an object representing subscribing client information. This has two string properties, domain and uri.
    • A return value of true represents that the subscribe operation is permitted, else it is not permitted.

Return value

The return value is a boolean indicating success or failure. For a connection with role 'client', the return value will be false, since only the 'manager' role is allowed to manage.

connHandle.subscribe(topic:string, callback:function, eventCallback:function)

Parameters

connHandle
The connHandle is the object provided in a previous connect.
topic
The topic can contain wildcards (see Hub 1.0 spec).
callback
The callback is defined as function(success:boolean, subHandle:object). The callback may be invoked synchronously, just before returning from subscribe.
eventCallback
The eventCallback is called for each event on the subscribed topic. It is defined as function(connHandle:object, topic:string, data:string, publisherInfo:{domain:string, uri:string})
  • data is a string containing the event payload.
  • the other parameters should be clear from the context.

Return value

The method returns subHandle object which implements unsubscribe described in more details below as well as following auxiliary methods:

  • subHandle.isSubscribed() returns true if subscription is active.
  • subHandle.getConnHandle() returns the corresponding connHandle.
  • subHandle.getTopic() returns the corresponding topic.
  • subHandle.equals(anotherSubHandle:object) returns true if two subHandles represent the same subscription, else false.

subscribe call will always fail and return null if connHandle.isConnected() !== true.

subHandle.unsubscribe(callback:function)

Parameters

The connHandle, subHandle, callback are defined same as the subscribe method.

Return value

The return value is defined the same as in the subscribe method.

connHandle.publish({topic:string, data:string, [callback:function]})

Parameters

connHandle
The connHandle is the object provided in a previous connect.
topic
The topic does not contain wildcards (see Hub 1.0 spec).
data
The event payload
callback (optional)
A function(success:boolean, connHandle:object, topic:string). The callback may be invoked synchronously, just before returning from connect.

[question]What is the semantics of this? Does it garantuee successfully delivery to every subscriber? Also why pass topic but not data? [/question]

Return value

The return value is a boolean indicating success or failure.


Hub SPI

Providers are registered with the hub in the following data structure:

  OpenAjax.hub.providers.config = [ providerObjects: Object ]

which contains the classnames of the different providers in (decreasing) order of preference.

The providerObjects have to implement all the methods in the previous section as well as the following interface:

  providerObject = {
     boolean <- supportsCommunicationType(host: string)
     string  <- name()
     string  <- version()
  }
  • name() will return a unique provider name, preferrable a URI
  • version() will return a version number of the provider using the same approach as the version parameter in OpenAjax.hub.registerLibrary of Hub 1.0.

[TBD] version represented as [0-9]+(\.[0-9]+)* [a-zA-Z0-9 .:;] with the second part ignored for version comparison. For two versions which have identical numbers in the first first position, the numerically higher one has to be backwards-compatible to the other one. [/TBD]

Notes

  • Defining it as an object allows parameterization and potentially even multiple version of a given base class, i.e., more flexible as a string with the provider classname.
  • Just providing a single order of preference is rather crude but should help the case of dealing with providers which are client-side specific but optimized over generic ones (e.g., Gears vs SMash). You simply would have a provider list such as [ html5.hub, gears.hub, default.hub, ..., jsonReq.hub, subspace.hub, proxyIfr.hub ... ].

Extensions for the default cross-frame provider

List of Functions

The default provider for the "cross-frame" communicationType defines the following additional functions on the connHandle returned to a manager.

  • loadFrame()
  • unloadFrame()


Details

connHandle.loadFrame({clientName:string, frameURL:string, [parentElement:object], [loadCallback:function], [errorCallback:function], ...})

Parameters

clientName
It is a manager chosen name for the client, and need not be known to the client.
frameURL
It is the URL of the iframe to be loaded.
parentElement (optional)
It is the element to which this iframe will be added as a child. If not specified, the iframe is added to document.
loadCallback (optional)
It is defined as function(clientName:string), and is called when the iframe is successfully loaded and communication is established with it.
errorCallback (optional)
It is defined as function(clientName:string, errorMessage:string), and is called if the iframe does not successfully load or there is some error that occurs in communication sometime during the lifetime of this iframe.
other parameters (optional)
Any other parameters passed in the JavaScript object are assumed to be attributes of the iframe object (for example, the style attribute).

Return value

The return value is a boolean indicating success or failure.

connHandle.unloadFrame({clientName:string})

Parameters

clientName
It is the manager chosen name for the client, as defined previously.

Return value

The return value is a boolean indicating success or failure.


Other Requirements

The following are potential requirements that we need to decide whether Hub 1.1 will address, and if so, how.

Topic namespace management

Certain conventions may need to be adopted for the topic namespace, for various purposes such as (1) interoperability of different AJAX libraries , (2) concurrent non-interfering use of different AJAX libraries (such as in [5]), (3) development of reusable widgets and mashups. These conventions could be documented in the OpenAjax Registry.

For (3), this may include conventions about what parts of the topic namespace are public, are for point-to-point communication etc.

Limited history (last message)

A requirement has been raised for a simplified data persistence feature, where a new subscriber to a topic will get the last message published on that topic prior to the subscription. This is intended to simplify application state initialization of new subscribers.

Topic Payload Typing

For a particular topic, the knowledge of the type of the message payloads could be useful. The type could be a JSON schema, or a string name that is known to have some meaning, like "vcard".


Miscellaneous Implementation Notes

A hub-instance is not constrained in its physical/implementation topology. A hub-instance may be distributed across all its clients. This distributed hub-instance may have a physical star-topology that corresponds one-to-one with the logical star-topology (manager at the center and clients on the outside). It may have a physical topology that is a tree with more than 2 levels, and the manager at the root. It may even have some sort of graph topology. In this document we will only be concerned with the logical topology of a hub-instance, which is always a star-topology.

Personal tools