Skip to content

Programming Reference: ONMjs.Store Class

ChrisRus edited this page Nov 12, 2013 · 14 revisions

Summary

Class ONMjs.Store is an in-memory, synchronous hierarchical object store that is either default constructed, or constructed with a JSON string. An ONMjs.Store is said to be bound to a specific ONMjs.Model at construction time which dictates the store's address space, as well as the set of addressable objects the store may contain at run-time.

Every ONMjs.Store class instance is unique insofar as the data it contains is specific to the store instance. This is true even in cases when two store's are bound to the same ONMjs.Model. You may use as many or as few instances of ONMjs.Store in your application as required. And, they may be bound to the same, or different models.

ONMjs.Store provides the primary run-time API leveraged by application logic to create and remove data components from the store, and for registering ONMjs observer routines that monitor the store for data changes, and react to these changes in application-defined ways. Additionally, ONMjs store provides helper methods leveraged by observer routines for storing private implementation data.

If an error occurs during ONMjs.Store construction, an exception is thrown.

Construction

    try {
        var store = new ONMjs.Store(model, jsonString);
    } catch (exception) {
        /* exception is a string containing a stack trace and context-specific error information */
    }

Parameters:

  • model - (required) a reference to an ONMjs.Model class instance.
  • jsonString - (optional) JSON string that is deserialized and used to initialize the store instance.

Properties

ONMjs.Store.description

A human-readable description of this Store (obtained directly from the bound Model).

ONMjs.Store.jsonTag

The outer JSON object name used by this Store (obtained directly from the bound Model).

ONMjs.Store.label

A human-readable label of this Store (obtained directly from the bound Model).

ONMjs.Store.model

Reference to the ONMjs.Model instance bound to this ONMjs.Store at construction.

Data API Methods

ONMjs.Store's data API comprises a small collection of methods leveraged by your application logic to create and remove data components, access specific data namespaces within the Store, and serialize the entire contents of the store to a JSON string.

ONMjs.Store.createComponent

    var namespace = store.createComponent(address);

Parameters:

  • address - (required) reference to an ONMjs.Address class instance specifying the address of the component's root namespace.

Return:

  • Returns an ONMjs.Namespace instance if successful.
  • Throws an exception if the requested component cannot be created.

Remarks:

The specified ONMjs.Address reference must meet three criteria:

  • The Address must be bound to the same Model as the Store.
  • The Address must specify the root namespace of a component defined in the bound Model.
  • The Address must be unresolved (i.e. a reference to an object that does not already exist in the Store).

ONMjs.Store.removeComponent

    store.removeComponent(address);

Parameters:

  • address - (required) reference to an ONMjs.Address class instance specifying the address of the component's root namespace.

Return:

  • Returns an ONMjs.Namespace instance if successful (see remarks).
  • Throws an exception if the requested component cannot be removed.

Remarks:

The specified ONMjs.Address reference must meet three criteria:

  • The Address must be bound to the same Model as the Store.
  • The Address must specify the root namespace of a component defined in the bound Model.
  • The Address must be resolvable (i.e. a reference to an object that exists in the Store).

Upon successful removal of a data component, ONMjs.Store.removeComponent returns a valid instance of ONMjs.Namespace that may be used to access the actual data via the ONMjs.Namespace.data method. Note that the removed component's data is no longer managed by ONMjs.Store at this point. Typically, callers of ONMjs.Store.removeComponent ignore the return value which results in the resource being freed during subsequent garbage collection.

ONMjs.Store.openNamespace

var namespace = store.openNamespace(address);

Parameters:

  • address - (required) reference to an ONMjs.Address class instance specifying the address of the namespace to open.

Return:

  • Returns an ONMjs.Namespace instance if successful.
  • Throws an exception if the requested namespace cannot be opened (e.g. it doesn't exist).

Remarks:

The specified ONMjs.Address reference must meet two criteria:

  • The Address must be bound to the same Model as the Store.
  • The Address must be resolvable (i.e. a reference to an object that exists in the Store).

ONMjs.Store.toJSON

    storeJSON = store.toJSON(replacer, space);

Parameters:

Return:

  • Returns the serialized contents of the Store as a JSON string if successful.
  • Throws an exception if the Store cannot be serialized to JSON.

Remarks:

ONMjs.Store.toJSON is used to serialize the entire contents of the store to JSON. To serialize a subset of the contents, use ONMjs.Namespace.toJSON instead.

As with any object that you intend to serialize to JSON, cyclic references are not supported.

ONMjs was designed from the ground-up to ensure the efficiency of the toJSON method.

Observer Registration API Methods

ONMjs.Store leverages the Observer Pattern as the basis for separating application data from the application logic that operates on that data. Specifically, ONMjs.Store functions as a subject (i.e. that which is observed), and application logic is structured as one or more observer(s) (i.e. entities that react when the subject changes).

The ONMjs.Store methods registerObserver and unregisterObserver (detailed below) provide the means of connecting and disconnecting Observers from a Store. The protocol by which Observers are notified of changes to the contents of a Store (i.e. the subject) is defined by the ONMjs Data Change Signal Protocol.

ONMjs.Store.registerObserver

    var myObject = {
        observerInterface: {
            onObserverAttach: function(store, observerId) { ... },
            onNamespaceCreated: function(store, address, observerId) { ... },
            onObserverDetach: function(store, observerId) { ... }
        };

    observerId = store.registerObserver(myObject.observerInterface, myObject);

Parameters:

  • observerCallbackInterface - (required) a reference to a Javascript object containing zero or more callback functions defined by the ONMjs Data Change Signal Protocol.
  • observingEntityReference - (optional) a reference to the Javascript object that contains the observerCallbackInterface (e.g. a class instance).

Return:

  • Returns an opaque string that identifies the registration if successful.
  • Throws an exception if the observer cannot be registered.

Remarks:

The specific events dispatched by an ONMjs.Store in response to data change events and their corollary callback functions are defined by the ONMjs Data Change Signal Protocol. All callback functions are optional; you may implement as many or few of them as you need.

Every call to ONMjs.Store.registerObserver creates a unique observer registration that is tracked with the returned observerId string.

The order that calls are made to ONMjs.Store.registerObserver does not matter. ONMjs.Store treats all registered observers as equals and dispatches data change events to registered observers in a random order that is not derived from the order in which they were registered. The reasons for this are subtle but have to do with ensuring that Observers are truly coupled only to your data model, and not to each other in subtle ways that prevent their general re-use in other projects.

The second parameter, observingEntityReference is optional but recommended. If specified, the observingEntityReference is copied into ONMjs.Store's internal observer registration table to make it simpler to debug complex scenarios where there are multiple observers registered on the same Store. But, that's all it's used for.

ONMjs.Store.unregisterObserver

    store.unregisterObserver(observerId);

Parameters:

  • observerId - (required) an opaque observer registration ID string obtained from a previous call to ONMjs.Store.registerObserver.

Return:

  • Returns no semantically useful information if successful.
  • Throws an exception if the specified observer cannot be unregistered.

Remarks:

Once an observer has been unregistered, its observer ID is invalid and cannot be re-used.

Unregistering an observer automatically removes any registration-specific observer state data that may have been allocated via calls to ONMjs.openObserver*State methods.

Observer Helper API Methods

Observers typically have to manage a lot of run-time state data that is derived from application data and/or the model meta-data that describes it. Although the semantics of this data are highly dependent on the application, the general sub-problem of keeping track of this information is generic. ONMjs.Store provides several helper methods that may be leveraged in Observer implementation code to conveniently obtain private data object(s) expressly for the purpose of storing derived run-time state information in a consistent and efficient manner.

Use of this facility is optional but highly recommended as it

ONMjs.Store.openObserverState

    observingObject = {
        observerInterface: {
            onAttachObserverBegin: function(store, observerId) {
                var observerStateObject = store.openObserverState(observerId);
                /* ... */
            }
        }
    };
    observerId = store.registerObserver(observerInterface, observingObject);

Parameters:

  • observerId - (required) an opaque observer registration ID string.

Return:

  • Returns a reference to a simple Javascript data object that an observer may use to store registration-specific run-time data.
  • Throws an exception on error.

Remarks:

To simplify the task of keeping track of all of this information, ONMjs.Store provides a private, registration-specific storage object to any observer that requests it via the ONMjs.Store.openObserverState method.

Observer state data is automatically disposed when ONMjs.Store.unregisterObserver is called.

ONMjs.Store.openObserverComponentState

    observingObject = {
        observerInterface: {
            onComponentCreated: function(store, address, observerId) {
                var observerComponentStateObject = store.openObserverComponentState(observerId, address);
                /* ... */
            }
        }
    };
    observerId = store.registerObserver(observerInterface, observingObject);

Parameters:

  • observerId - (required) an opaque observer registration ID string.
  • address - (required) a reference to a ONMjs.Address instance that references a component's root namespace or one of its subnamespaces.

Return:

  • Returns a reference to a simple Javascript data object that an observer may use to store run-time data specific to the component specified by address.
  • Throws an exception on error.

Remarks:

ONMjs.Store.openObserverComponentState is a thin wrapper around ONMjs.Store.openObserverNamespaceState. If the specified address references the root namespace of a component, then the call is equivalent to a call to ONMjs.Store.openObserverNamespaceState. If address specifies a subnamespace of a component, ONMjs.Store.openObserverComponentState uses the component's root namespace address instead of the specified address.

ONMjs.Store.openObserverNamespaceState

    observingObject = {
        observerInterface: {
            onNamespaceCreated: function(store, address, observerId) {
                var observerNamespaceStateObject = store.openObserverNamespaceState(observerId, address);
                /* ... */
            }
        }
    };
    observerId = store.registerObserver(observerInterface, observingObject);

Parameters:

  • observerId - (required) an opaque observer registration ID string.
  • address - (required) a reference to a ONMjs.Address instance that references a component's root namespace or one of its subnamespaces.

Return:

  • Returns a reference to a simple Javascript data object that an observer may use to store run-time data specific to the namespace specified by address.
  • Throws an exception on error.

Remarks:

Observers typically have to manage a lot of complicated run-time state information that is typically derived from application and/or model data (i.e. meta-data).

To simplify the task of keeping track of all of this information, ONMjs.Store provides a private, registration AND namespace-specific storage object to any observer that requests it via the ONMjs.Store.openObserverNamepsaceState method.

Observer state data is automatically disposed when ONMjs.Store.unregisterObserver is called (this includes any and all observer namespace state objects allocated by the observer via calls to ONMjs.Store.openObserverNamespaceState). However, ONMjs.Store does not automatically dispose of individual namespace state objects. You must do this yourself via a call to ONMjs.Store.removeObserverNamespaceState (see below).

ONMjs.Store.removeObserverNamespaceState

    observingObject = {
        observerInterface: {
            onNamespaceRemoved: function(store, address, observerId) {
                store.removeObserverNamespaceState(observerId, address);
                /* ... */
            }
        }
    };
    store.unregisterObserver(observerId);

Parameters:

  • observerId - (required) an opaque observer registration ID string.
  • address - (required) a reference to a ONMjs.Address instance that references a component's root namespace or one of its subnamespaces.

Return:

  • Returns no semantically useful information if successful.
  • Throws an exception if the specified namespace observer state cannot be removed.

Remarks:

To conserve memory, you should remove allocated observer namespace state when you no longer need it. ONMjs does not do this automatically for you because it doesn't have any way of knowing the semantics of the state data you have allocated.

ONMjs.Store.removeObserverState

    try {
        store.removeObserverState(observerId);
    } catch (exception) {
        /* .... handle the error. */
    }

Parameters:

  • observerId - (required) an opaque observer registration ID string.

Return:

  • Returns no semantically useful information if successful.
  • Throws an exception if the specified observer state cannot be removed.

Remarks:

ONMjs automatically removes all private observer state data associated with an observer ID automatically when the observer is unregistered via a call to ONMjs.Store.unregisterObserver. To reset the private state associated with an observer manually, call the removeObserverState method.

Utility API Methods

ONMjs.Store.validateAddressModel

    var compatibleAddress = store.validateAddressModel(address);
    if (!compatibleAddress) { throw "This address is bound to a different model than the store!"; }

Parameters:

  • address - (required) any ONMjs.Address class instance reference

Return:

  • Boolean: returns true iff the specified address is bound to the same Model as the Store. Otherwise false.
  • Throws an exception on error.

Copyright (C) 2013 Christopher D. Russell