The Nexus

From wiki.gpii
Jump to: navigation, search

Overview

The Nexus is a technology designed to make it easier to connect together components that have been implemented using different programming languages, toolkits, and frameworks. The Nexus is being developed specifically for Prosperity4All to help ensure that technological diversity is sustainable and cost-effective. It provides a foundational infrastructure to support the reuse of accessible components and building blocks, aiming to reduce redundant development and make it easier to share code when developing a variety of applications and adaptive technologies. The goal of the Nexus is to make it possible to assemble applications and assistive technologies from a variety of pre-built components, even when these components have been implemented using different technologies, and to allow for different components to understand, react to, and control each other in more integral ways than is possible with conventional APIs. The Nexus provides an interoperability scheme and data interchange format that is simple, semantic, and broadly applicable to a variety of programming styles and technologies. It is architected in a manner that makes it possible to implement new transport protocols and language/environmental endpoints as needed.

In contrast to conventional platform accessibility APIs, the Nexus aims to support the interoperable transfer of an application or component’s state, rather than simply describing its “view” or appearance. This opens the possibility of creating assistive technologies or cross-component integrations that are structural in nature, as opposed to just presentational. This allows a Nexus-compatible component to provide a substantially different rendering or an alternative means for controlling another component’s functionality.

The Nexus provides a means for developers to externalize their application or component’s model, enabling it to be observed and modified by other components—even those that are running in a different process space or have been implemented in a different programming language. The Nexus provides a transport-agnostic, reactive implementation of the state transfer principle of REST. Nexus clients have the ability to observe and operate upon an application’s model as a stream of real-time change events. In this respect, the Nexus can be understood as providing a form of functional reactive programming (FRP) in which models represent time-varying values that can be transformed, aggregated, or reduced using declarative model relay functions. In order to be as broadly useful as possible, the Nexus does not impose a complex high-level semantic for application states or roles. However, the Nexus’ capabilities are sufficiently comprehensive to support the implementation of higher-level, domain- or community-specific semantics and standards on top.

Motivations for the Nexus

The value proposition of Prosperity4All, from a technical and architectural perspective is that, in order to make an impact on the cost and quality of assistive technologies and accessible applications, we must support developers wherever they are, regardless of platform, operating system, programming language, or toolkits used. The P4A Developer Space aims to gather together as diverse a set of software building blocks, components, frameworks, example code, and technical idioms as possible in order to promote the reuse, adaptation, and iterative improvement of accessible tools. This will potentially lead to a reduction in the cost and complexity of building the next generation of accessibility software.

However, technical heterogeneity can be difficult to manage. It runs the risk that crucial functionality required for accessibility and autopersonalization ends up being limited to particular programming languages or toolkits, leaving other developers to fend for themselves or invest in redundant, overlapping development of foundational infrastructure. Since the community of developers creating accessible tools is so relatively small, there is a need to foster reuse and collaborative development efforts. As Stephen Kell puts it, without specific tools to support integration, software has a “tendency to grow in silos,” producing disconnected “islands of functionality”. While not every component has the potential to be widely reused and interconnected with other types of software, the Prosperity4All ecosystem nonetheless needs technologies that are specifically focussed on strategies for interoperable software composition.

A centralized, top-down architectural approach that attempts to comprehensively define and control a single shared API across the dizzying array of real-world platforms and technologies in the Prosperity4All ecosystem is bound to fail. Instead, developers need a means to bridge their technology choices with those of others—a mechanism for composing new software using existing components in the Developer Space.

We examined other integration technologies and architectures in the literature prior to designing the Nexus. A number of strands are present within the field. Often, however, the emphasis is placed on Enterprise Application Integration (EAI) technologies and Systems Integration (SI) methodologies, which are both predominantly organizational in nature. Most EAI approaches emphasize specific business or institutional structures within the enterprise, and as a result have tended to produce technology solutions that are primarily centralized and intended to be managed by large IT teams. Similarly, the Systems Integration literature promotes the use of specialized software development methodologies within a single organization to better produce a consistent architecture and APIs across business units.

Since Prosperity4All aims to support very different scales of software development teams, from single-developer startups to large open source communities and commercial vendors, a methodological approach that prescribes particular management or development practices will not fit our diverse ecosystem. Similarly, many technologies suited for back-end systems and single enterprises will fail to support the many different contexts and use cases of the components within the Prosperity4All ecosystem.

Commercial integration solutions have tended either to cater to large enterprise IT requirements or have pursued low-level protocols for interoperability such as MQTT, CoAP, etc., which do not provide any form of higher-level messaging semantics, and require additional API contracts and agreement on payload structure and meaning.

Technologies such as Enterprise Service Buses (ESBs) are often promoted as a solution to integration requirements. Due to their all-in-one, server-based approach, however, they tend to be large, complex to setup, and resource-intensive. Evidence suggests that the advantages of ESBs are mainly found within centralized, single-organization IT infrastructures. For distributed, heterogeneous end-user software products, which are used in diverse contexts and often without the benefit of centralized support staff, ESBs represent significant technical complexity and require specialized technology knowledge on the part of developers.

In contrast to enterprise service and messaging buses, the Nexus aims to provide developers with an integration technology that is simple to configure, requires minimal resources on a user’s computer, and which provides a consistent and straightforward semantic for bidirectionally sharing state information. And, in contrast to direct coupling between components, the Nexus can support optional bindings, allowing for looser dependencies between components in cases where the user does not have some component installed or running.

An interesting variant integration technology in the literature is Hydra, a REST-inspired Hypermedia-driven Web API which was active between 2013 and 2014, and was the focus of an active W3C Community Group. It is now the basis of an ongoing project “LinkSmart” steered by FHG. Hydra, like the Nexus, shares an emphasis on standard web protocols and document formats (HTTP, JSON and JSON schema). Hydra enables live web services to be set up based on API contracts specified in JSON-LD. However, a key aspect of integration infrastructure is not addressed in the Hydra system: how relationships are set up and torn down between data streams, and what the correspondence is between a stream of state written by one client and that read by another. Whilst “self-describing” web services are indeed a cornerstone of REST, Hydra’s self-describing capability can only be effectively consumed from an extremely mature and complex toolchain and application idiom, the likes of which are not commonly deployed. In our practical experience, even meeting the baseline requirements of REST can be difficult for many developers, and many ostensibly RESTful APIs are, in practice, just remote procedure call interfaces over HTTP with no support for formalized resource description or linked data. The aim of the Nexus is to reduce implementation costs in areas of application design more urgent than resource description or protocol conformance by providing an implementation substrate that allows the creation of real-world integrations that enable interoperability between users of variant implementation technologies and protocols.

The Nexus does not invent new transport protocols, but simply uses protocols that already exist as part of standardized web technologies such as HTTP and WebSockets. The protocols named here are not exclusive, and it would be perfectly possible to construct bindings to the Nexus over other protocols such as MQTT and CoAP if they were found to be sufficiently widespread and usefully adopted within the Prosperity4All ecosystem. The intent of the Nexus and its protocols is to usefully constrain semantics in a way that will promote genuine interoperability—that is, to promote the chance that messages may be successfully understood and acted upon, with minimal fresh programming-language-level development and architectural overhead, rather than that they may merely be received and decoded, which is the province of the underlying protocols themselves.

Nexus Architecture

Overview

The Nexus consists of a library implemented in JavaScript and a service implemented using Node.js. Its API is provided in both local and remote forms. The local API simply takes the form of JavaScript function calls made to the Nexus library, which a developer can include locally in the same process as the components they want to integrate (e.g. in a web browser, a Node.js process, or other). The remote API takes the form of JSON payloads sent over plain HTTP and WebSockets protocols to a well-known endpoint. The two forms of the protocol are isomorphic and every message which can be sent in one form has a direct equivalent in the other.

The primary responsibility of the Nexus is to manage a tree of components referred to as model peers, which publicly represent the state of “native” components (i.e. those that are integrated with the Nexus). Model peers contain data models that consist of arbitrary trees of JSON objects and values. Clients of the Nexus can use its API to:

  • define model peer components
  • retrieve metadata about model peers
  • instantiate model peers in the Nexus component tree
  • destroy instantiated peers
  • define transducers known as model relays to convert values into other formats and representations and to coordinate, transform, or reduce model state amongst a collection of cooperating model peers
  • bind listeners to arbitrary paths within a model
  • publish changes in their own internal application state by making change requests to modify the state of their model peers in the Nexus, which will cause change events to fire to any listeners at the specified model path

Multiple clients can interact with the Nexus simultaneously, and changes can be streamed both to and from the Nexus in a manner that supports a variety of one to one, one to many, and many to many relays.

One of the advantages of the Nexus’ use of JSON-encodable change messages is that they can be serialized or archived for various purposes, for example, to support scripting and replaying user actions, or logging, monitoring and analytics.

{
  type: “add",
  path: “menu.selectedItem",
  value: “Motorcyle”,
  oldValue: “Bicycle”                        
}

Example 1: A Nexus-compatible change specification expressed as a JSON object.

Nexus as Integration Domain

The Nexus forms what has been described in the literature as an integration domain. An alternative viewpoint might cast it as a system for composition of synthesized web services. The Nexus encourages all integrated components to follow an integral model whereby all interesting states are represented by distinct, fully realised bodies of publically addressable state. As a result, component composition simply consists of the composition of these bodies of state, and component interfacing consists of transduction of corresponding values of this state, which are brought into equivalence by means of (primarily) symmetric lenses.

This correspondence between the values of the state itself, what we refer to under the name Model Relay, is a much more simple thing than what often goes by the name “model” in the wider literature. Here, when we refer to a “model,” we are not referring to transformations between the structures of state machines, but rather simply the state itself. However, wherever we succeed in representing the correspondences between state as proxies for the states of any respective machines, naturally we will succeed in putting any supervening machines into correspondence as well, without necessarily becoming aware of the fact.

A Guided Example

Below is a simple interaction between two participants, one of whom, Participant A, advertises a piece of UI exhibiting a toggleable state of some kind—for example, a hideable panel or a checkbox. The other, Participant B, advertises a source of timed but otherwise undifferentiated events—for example, a simple puffer switch or jelly bean switch. Either Participant B or a third participant can provide a relay specification to transduce the stream of switch events onto the toggleable target. Two things are required: the specification of the addresses of the source and target (via a CSS-style selector system) the exact nature of the transduction rule.

This example uses the local Nexus API for clarity, but bear in mind that either or both the switch and the toggle UI could be hosted in different processes on different machines, and use the HTTP/WebSockets Remote API style for both type definitions and binding to the Nexus, which might be within either of those processes or a 3rd process.

First, Participant A must define and register their model peer component with the Nexus:

// Set up the definition of the toggleable type
gpii.defaults("participant-a.toggleable", {
  parentGrades: "gpii.modelComponent",
  model: {
    toggle: false
  }
});

Secondly, they need to construct an instance of the toggleable component in the Nexus, which will serve as a peer for an individual UI control written in Participant A’s chosen technology:

// Construct a particular instance of the toggleable in the Nexus, 
// to peer with an individual UI control written in some native technology.
var toggle1 = gpii.construct("participant-a.application.toggle1", {
  type: "participant-a.toggleable",
});

Participant A will also need to listen for state changes in their model peer component, in case other clients of the Nexus want to make changes to it:

toggle1.addModelListener("toggle", function () {
  // bind to actual UI state here
});

Next, Participant B will define their switch component:

// Define the "type" for our switch here
gpii.defaults("participant-b.switch", {
  parentGrades: "gpii.modelComponent",
  model: {
    count: 0 // a piece of "integral state" 
             // representing how many times 
             // the switch has been operated
    }
});

When Participant B instantiates their switch, they will bind it to Participant A’s toggle component, defining a model relay to transform the state of the toggle component into a format more suitable for their application’s requirements:

var switchPeer = gpii.construct("participant-b.interface.switch1", {
  type: "participant-b.switch",
  modelRelay: {
    source: "{switch1}.model.count",
    // A selector uniquely identifying participant A's toggle1 switch       
    target: "{/ participant-a.toggleable&toggle1}.model.toggle",

    // Define a relay to transform between component model states.
    singleTransform: {
        type: "gpii.transforms.countToToggle",
        forward: "liveOnly",  // only bind outgoing changes once 
                              // the link is established
        backward: "initOnly", // only bind incoming changes during startup
                              // the switch's state is not 
                              // generally writeable, but the relay needs 
                              // to acquire phase on startup
        }
    }
});

Then, Participant B can listen to the switch’s actual state in their application, and periodically issue changes to the Nexus in this style:

switchHardware.addListener(function () {
    switchPeer.applier.change("count", switchPeer.model.count + 1);
});


Securing the Nexus

Components integrated with the Nexus will be able to build on component grades, model transforms, and other functionality that has been provided with the Nexus, or created by others. However, there will be situations where we will want to provide access controls for it, and we must also provide users with the ability to limit access to parts of the Nexus. For example, we will want to ensure that components created using the Nexus remote API are unable to access the filesystem of the device on which the Nexus is running.

We will implement access controls within the Nexus to limit read and write access to grades, components, and other parts of the Nexus. Whenever the Nexus processes a request that would require access to named components, an access policy specification will be consulted. The policy will take the form of a whitelist, together with access rules (such as read access or write access). For example, the construction of the “participant-b.interface.switch1” component above would require read access to the “fluid.modelComponent” grade and the “gpii.transforms.countToToggle” transform:

{
    "fluid.modelComponent": {
        "read": true,
        "write": false
    },
    "gpii.transforms.countToToggle": {
        "read": true,
        "write": false
    }
}

Example 2: An declarative access control document for the Nexus, specifying the access controls for a model peer grade and a model transducer, respectively.

Relationship to Other GPII Technologies

The Nexus is implemented using several of the shared architectural idioms and technical frameworks that comprise the GPII Development Platform. In particular, the Nexus is built using a Prosperity4All SP2 toolkit, Infusion. The use of Infusion provides the Nexus with many of the foundational tools for creating model peers and propagating model changes throughout the system. The Nexus significantly builds on this foundation, requiring the development of new APIs, REST endpoints, and security features for Prosperity4All that support the integration of diverse components, including those that are not implemented in JavaScript.

The Nexus’ remote API also uses Node.js and the Kettle server framework in order to provide HTTP and WebSocket endpoints, ensuring that it shares the broad deployability, unit testability, and declarative configurability of other GPII services.

In the future, the Nexus may be optionally installed alongside the GPII’s Realtime Framework, which was developed as part of the Cloud4All project and is now being brought to production by the APCP project. The Nexus’ functionality complements the GPII framework by providing new APIs for building and integrating next-generation assistive technologies, many of which will benefit from the autopersonalization features of the realtime framework. In this scenario where the Nexus is deployed alongside the realtime framework, a Nexus instance will be available wherever there is a GPII Flow Manager.

Status and Next Steps

The Nexus is currently under active development and testing. Its source code is licensed openly and is available in Github, following the GPII Technical Governance policies. The Nexus has been integrated with the Prosperity4All Quality Infrastructure, where it is built and tested each time new changes are committed to the Nexus repository.

The core Nexus API specification, described below, has been implemented, including support for the following operations:

  1. Registering, instantiating, and destroying model peers
  2. Defining model relays that transduce state between models
  3. Listening for and publishing changes to Nexus-managed models

Currently, we have implemented support for both the local JavaScript API and the remote API. The remote API can be used by any client that supports WebSockets. New transports may be added if there is demand from developers who host their components in the Developer Space. Strategies for securing the Nexus APIs have been designed, and are in the process of being specified and then implemented.

So far, we have integrated and tested the Nexus with three different technologies used within Prosperity4All’s SP2, including:

  • AsTeRICS and Java
  • Fluid Infusion components
  • W3C Web Components

Some further effort is required to generalize these integrations into reusable “connectors” that can be used with any component written using the technologies mentioned above. New integrations will also be added based on collaborations with SP2 and SP3 developers.

Nexus API

The Nexus v1.0 API is described in detail on the Nexus API page. This document describes each of the primary operations that can be performed by a client of the Nexus and the required payloads. For each operation, we specify a local API for in-process JavaScript clients of the Nexus and a REST-style remote API for clients implemented in other languages or running in another process space.

The Visible Nexus

The Visible Nexus is a collection of tools for perceiving, authoring and debugging applications developed using the GPII Nexus.

From a technical perspective, the Visible Nexus is an augmentation of the GPII Nexus, which is implemented as a Kettle application. It consists of a mix-in grade that can be applied to any Nexus instance, in order to endow it with a self-served web interface which allows the contents of the Nexus to be queried, represented in a visual graph form, and manipulated in some simple ways.

The current implementation demonstrates the essential affordances of the system. Any numbers of clients may simultaneously connect to the same Nexus interface, and interact with the same shared substrate. Any updates to the component structure or the models attached to the components, whether triggered internally or by one of the clients, are immediately transmitted to the UIs of any connected clients.

Visible Nexus.png

The Visual Nexus user interface features basic keyboard accessibility and basic ARIA labelling of the component structure and members.

Active development of the Visual Nexus is currently being done in several interrelated Github repositories: