mirror of
https://github.com/nasa/openmct.git
synced 2025-06-17 14:48:13 +00:00
[Persistence] Rename bundle
Rename bundle for queued persistence. WTD-1033.
This commit is contained in:
@ -0,0 +1,6 @@
|
||||
/*global define*/
|
||||
|
||||
define({
|
||||
REVISION_ERROR_KEY: "revision",
|
||||
OVERWRITE_KEY: "overwrite"
|
||||
});
|
54
platform/persistence/queue/src/PersistenceFailureDialog.js
Normal file
54
platform/persistence/queue/src/PersistenceFailureDialog.js
Normal file
@ -0,0 +1,54 @@
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
['./PersistenceFailureConstants'],
|
||||
function (PersistenceFailureConstants) {
|
||||
"use strict";
|
||||
|
||||
var OVERWRITE_CANCEL_OPTIONS = [
|
||||
{
|
||||
name: "Overwrite",
|
||||
key: PersistenceFailureConstants.OVERWRITE_KEY
|
||||
},
|
||||
{
|
||||
name: "Cancel",
|
||||
key: "cancel"
|
||||
}
|
||||
],
|
||||
OK_OPTIONS = [ { name: "OK", key: "ok" } ];
|
||||
|
||||
/**
|
||||
* Populates a `dialogModel` to pass to `dialogService.getUserChoise`
|
||||
* in order to choose between Overwrite and Cancel.
|
||||
*/
|
||||
function PersistenceFailureDialog(failures) {
|
||||
var revisionErrors = [],
|
||||
otherErrors = [];
|
||||
|
||||
// Place this failure into an appropriate group
|
||||
function categorizeFailure(failure) {
|
||||
// Check if the error is due to object revision
|
||||
var isRevisionError = ((failure || {}).error || {}).key ===
|
||||
PersistenceFailureConstants.REVISION_ERROR_KEY;
|
||||
// Push the failure into the appropriate group
|
||||
(isRevisionError ? revisionErrors : otherErrors).push(failure);
|
||||
}
|
||||
|
||||
// Separate into revision errors, and other errors
|
||||
failures.forEach(categorizeFailure);
|
||||
|
||||
return {
|
||||
title: "Save Error",
|
||||
template: "persistence-failure-dialog",
|
||||
model: {
|
||||
revised: revisionErrors,
|
||||
unrecoverable: otherErrors
|
||||
},
|
||||
options: revisionErrors.length > 0 ?
|
||||
OVERWRITE_CANCEL_OPTIONS : OK_OPTIONS
|
||||
};
|
||||
}
|
||||
|
||||
return PersistenceFailureDialog;
|
||||
}
|
||||
);
|
74
platform/persistence/queue/src/PersistenceFailureHandler.js
Normal file
74
platform/persistence/queue/src/PersistenceFailureHandler.js
Normal file
@ -0,0 +1,74 @@
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
['./PersistenceFailureDialog', './PersistenceFailureConstants'],
|
||||
function (PersistenceFailureDialog, PersistenceFailureConstants) {
|
||||
"use strict";
|
||||
|
||||
function PersistenceFailureHandler($q, dialogService, persistenceService) {
|
||||
// Refresh revision information for the domain object associated
|
||||
// with htis persistence failure
|
||||
function refresh(failure) {
|
||||
// Perform a new read; this should update the persistence
|
||||
// service's local revision records, so that the next request
|
||||
// should permit the overwrite
|
||||
return persistenceService.readObject(
|
||||
failure.persistence.getSpace(),
|
||||
failure.id,
|
||||
{ cache: false } // Disallow caching
|
||||
);
|
||||
}
|
||||
|
||||
// Issue a new persist call for the domain object associated with
|
||||
// this failure.
|
||||
function persist(failure) {
|
||||
var undecoratedPersistence =
|
||||
failure.domainObject.getCapability('persistence');
|
||||
return undecoratedPersistence &&
|
||||
undecoratedPersistence.persist();
|
||||
}
|
||||
|
||||
// Retry persistence for this set of failed attempts
|
||||
function retry(failures) {
|
||||
// Refresh all objects within the persistenceService to
|
||||
// get up-to-date revision information; once complete,
|
||||
// reissue the persistence request.
|
||||
return $q.all(failures.map(refresh)).then(function () {
|
||||
return $q.all(failures.map(persist));
|
||||
});
|
||||
}
|
||||
|
||||
// Handle failures in persistence
|
||||
function handleFailures(failures) {
|
||||
// Prepare dialog for display
|
||||
var dialogModel = new PersistenceFailureDialog(failures),
|
||||
revisionErrors = dialogModel.model.revised;
|
||||
|
||||
// Handle user input (did they choose to overwrite?)
|
||||
function handleChoice(key) {
|
||||
// If so, try again
|
||||
if (key === PersistenceFailureConstants.OVERWRITE_KEY) {
|
||||
return retry(revisionErrors);
|
||||
}
|
||||
}
|
||||
|
||||
// Prompt for user input, the overwrite if they said so.
|
||||
return dialogService.getUserChoice(dialogModel)
|
||||
.then(handleChoice);
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Handle persistence failures by providing the user with a
|
||||
* dialog summarizing these failures, and giving the option
|
||||
* to overwrite/cancel as appropriate.
|
||||
* @param {Array} failures persistence failures, as prepared
|
||||
* by PersistenceQueueHandler
|
||||
*/
|
||||
handle: handleFailures
|
||||
};
|
||||
}
|
||||
|
||||
return PersistenceFailureHandler;
|
||||
}
|
||||
);
|
57
platform/persistence/queue/src/PersistenceQueue.js
Normal file
57
platform/persistence/queue/src/PersistenceQueue.js
Normal file
@ -0,0 +1,57 @@
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
[
|
||||
'./PersistenceQueueImpl',
|
||||
'./PersistenceQueueHandler',
|
||||
'./PersistenceFailureHandler'
|
||||
],
|
||||
function (
|
||||
PersistenceQueueImpl,
|
||||
PersistenceQueueHandler,
|
||||
PersistenceFailureHandler
|
||||
) {
|
||||
"use strict";
|
||||
|
||||
|
||||
/**
|
||||
* The PersistenceQueue is used by the QueuingPersistenceCapability
|
||||
* to aggregrate calls for object persistence. These are then issued
|
||||
* in a group, such that if some or all are rejected, this result can
|
||||
* be shown to the user (again, in a group.)
|
||||
*
|
||||
* This constructor is exposed as a service, but handles only the
|
||||
* wiring of injected dependencies; behavior is implemented in the
|
||||
* various component parts.
|
||||
*
|
||||
* @param $timeout Angular's $timeout
|
||||
* @param {PersistenceQueueHandler} handler handles actual
|
||||
* persistence when the queue is flushed
|
||||
* @param {number} [DELAY] optional; delay in milliseconds between
|
||||
* attempts to flush the queue
|
||||
*/
|
||||
function PersistenceQueue(
|
||||
$q,
|
||||
$timeout,
|
||||
dialogService,
|
||||
persistenceService,
|
||||
PERSISTENCE_QUEUE_DELAY
|
||||
) {
|
||||
// Wire up injected dependencies
|
||||
return new PersistenceQueueImpl(
|
||||
$timeout,
|
||||
new PersistenceQueueHandler(
|
||||
$q,
|
||||
new PersistenceFailureHandler(
|
||||
$q,
|
||||
dialogService,
|
||||
persistenceService
|
||||
)
|
||||
),
|
||||
PERSISTENCE_QUEUE_DELAY
|
||||
);
|
||||
}
|
||||
|
||||
return PersistenceQueue;
|
||||
}
|
||||
);
|
79
platform/persistence/queue/src/PersistenceQueueHandler.js
Normal file
79
platform/persistence/queue/src/PersistenceQueueHandler.js
Normal file
@ -0,0 +1,79 @@
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Handles actual persistence invocations for queeud persistence
|
||||
* attempts, in a group. Handling in a group in this manner
|
||||
* also allows failure to be handled in a group (e.g. in a single
|
||||
* summary dialog.)
|
||||
* @param $q Angular's $q, for promises
|
||||
* @param {PersistenceFailureHandler} handler to invoke in the event
|
||||
* that a persistence attempt fails.
|
||||
*/
|
||||
function PersistenceQueueHandler($q, failureHandler) {
|
||||
|
||||
// Handle a group of persistence invocations
|
||||
function persistGroup(ids, queue, domainObjects) {
|
||||
var failures = [];
|
||||
|
||||
// Try to persist a specific domain object
|
||||
function tryPersist(id) {
|
||||
// Look up its persistence capability from the provided
|
||||
// id->persistence object.
|
||||
var persistence = queue[id];
|
||||
|
||||
// Handle success
|
||||
function succeed(value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// Handle failure (build up a list of failures)
|
||||
function fail(error) {
|
||||
failures.push({
|
||||
id: id,
|
||||
persistence: persistence,
|
||||
domainObject: domainObjects[id],
|
||||
error: error
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
// Invoke the actual persistence capability, then
|
||||
// note success or failures
|
||||
return persistence.persist().then(succeed, fail);
|
||||
}
|
||||
|
||||
// Handle any failures from the full operation
|
||||
function handleFailure(value) {
|
||||
return failures.length > 0 ?
|
||||
failureHandler.handle(failures) : value;
|
||||
}
|
||||
|
||||
// Try to persist everything, then handle any failures
|
||||
return $q.all(ids.map(tryPersist)).then(handleFailure);
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
/**
|
||||
* Invoke the persist method on the provided persistence
|
||||
* capabilities.
|
||||
* @param {Object.<string,PersistenceCapability>} queue
|
||||
* capabilities to invoke, in id->capability pairs.
|
||||
* @param {Object.<string,DomainObject>} domainObjects
|
||||
* associated domain objects, in id->object pairs.
|
||||
*/
|
||||
persist: function (queue, domainObjects) {
|
||||
var ids = Object.keys(queue);
|
||||
return persistGroup(ids, queue, domainObjects);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return PersistenceQueueHandler;
|
||||
}
|
||||
);
|
94
platform/persistence/queue/src/PersistenceQueueImpl.js
Normal file
94
platform/persistence/queue/src/PersistenceQueueImpl.js
Normal file
@ -0,0 +1,94 @@
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* The PersistenceQueue is used by the QueuingPersistenceCapability
|
||||
* to aggregrate calls for object persistence. These are then issued
|
||||
* in a group, such that if some or all are rejected, this result can
|
||||
* be shown to the user (again, in a group.)
|
||||
*
|
||||
* This implementation is separate out from PersistenceQueue, which
|
||||
* handles the wiring of injected dependencies into an instance of
|
||||
* this class.
|
||||
*
|
||||
* @param $timeout Angular's $timeout
|
||||
* @param {PersistenceQueueHandler} handler handles actual
|
||||
* persistence when the queue is flushed
|
||||
* @param {number} [DELAY] optional; delay in milliseconds between
|
||||
* attempts to flush the queue
|
||||
*/
|
||||
function PersistenceQueueImpl($timeout, handler, DELAY) {
|
||||
var queue = {},
|
||||
objects = {},
|
||||
lastObservedSize = 0,
|
||||
pendingTimeout,
|
||||
flushPromise;
|
||||
|
||||
// Check if the queue's size has stopped increasing)
|
||||
function quiescent() {
|
||||
return Object.keys(queue).length === lastObservedSize;
|
||||
}
|
||||
|
||||
// Persist all queued objects
|
||||
function flush() {
|
||||
// Persist all queued objects
|
||||
flushPromise = handler.persist(queue, objects);
|
||||
|
||||
// When persisted, clear the active promise
|
||||
flushPromise.then(function () {
|
||||
flushPromise = undefined;
|
||||
});
|
||||
|
||||
// Reset queue, etc.
|
||||
queue = {};
|
||||
objects = {};
|
||||
lastObservedSize = 0;
|
||||
pendingTimeout = undefined;
|
||||
}
|
||||
|
||||
// Schedule a flushing of the queue (that is, plan to flush
|
||||
// all objects in the queue)
|
||||
function scheduleFlush() {
|
||||
function maybeFlush() {
|
||||
// Only flush when we've stopped receiving updates
|
||||
(quiescent() ? flush : scheduleFlush)();
|
||||
}
|
||||
|
||||
// If we are already flushing the queue...
|
||||
if (flushPromise) {
|
||||
// Wait until that's over before considering a flush
|
||||
flushPromise.then(maybeFlush);
|
||||
} else {
|
||||
// Otherwise, schedule a flush on a timeout (to give
|
||||
// a window for other updates to get aggregated)
|
||||
pendingTimeout = pendingTimeout ||
|
||||
$timeout(maybeFlush, DELAY, false);
|
||||
}
|
||||
}
|
||||
|
||||
// If no delay is provided, use a default
|
||||
DELAY = DELAY || 0;
|
||||
|
||||
return {
|
||||
/**
|
||||
* Queue persistence of a domain object.
|
||||
* @param {DomainObject} domainObject the domain object
|
||||
* @param {PersistenceCapability} persistence the object's
|
||||
* undecorated persistence capability
|
||||
*/
|
||||
put: function (domainObject, persistence) {
|
||||
var id = domainObject.getId();
|
||||
queue[id] = persistence;
|
||||
objects[id] = domainObject;
|
||||
scheduleFlush();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return PersistenceQueueImpl;
|
||||
}
|
||||
);
|
@ -0,0 +1,31 @@
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* The QueuingPersistenceCapability places `persist` calls in a queue
|
||||
* to be handled in batches.
|
||||
* @param {PersistenceQueue} queue of persistence calls
|
||||
* @param {PersistenceCapability} persistence the wrapped persistence
|
||||
* capability
|
||||
* @param {DomainObject} domainObject the domain object which exposes
|
||||
* the capability
|
||||
*/
|
||||
function QueuingPersistenceCapability(queue, persistence, domainObject) {
|
||||
var queuingPersistence = Object.create(persistence),
|
||||
id = domainObject.getId();
|
||||
|
||||
// Override persist calls to queue them instead
|
||||
queuingPersistence.persist = function () {
|
||||
queue.put(id, persistence);
|
||||
};
|
||||
|
||||
return queuingPersistence;
|
||||
}
|
||||
|
||||
return QueuingPersistenceCapability;
|
||||
}
|
||||
);
|
@ -0,0 +1,75 @@
|
||||
/*global define,Promise*/
|
||||
|
||||
/**
|
||||
* Module defining CoreCapabilityProvider. Created by vwoeltje on 11/7/14.
|
||||
*/
|
||||
define(
|
||||
['./QueuingPersistenceCapability'],
|
||||
function (QueuingPersistenceCapability) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Capability decorator. Adds queueing support to persistence
|
||||
* capabilities for domain objects, such that persistence attempts
|
||||
* will be handled in batches (allowing failure notification to
|
||||
* also be presented in batches.)
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function QueuingPersistenceCapabilityDecorator(
|
||||
persistenceQueue,
|
||||
capabilityService
|
||||
) {
|
||||
|
||||
function decoratePersistence(capabilities) {
|
||||
var originalPersistence = capabilities.persistence;
|
||||
if (originalPersistence) {
|
||||
capabilities.persistence = function (domainObject) {
|
||||
// Get/instantiate the original
|
||||
var original =
|
||||
(typeof originalPersistence === 'function') ?
|
||||
originalPersistence(domainObject) :
|
||||
originalPersistence;
|
||||
|
||||
// Provide a decorated version
|
||||
return new QueuingPersistenceCapability(
|
||||
persistenceQueue,
|
||||
original,
|
||||
domainObject
|
||||
);
|
||||
};
|
||||
}
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
function getCapabilities(model) {
|
||||
return capabilityService.getCapabilities(model)
|
||||
.then(decoratePersistence);
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Get all capabilities associated with a given domain
|
||||
* object.
|
||||
*
|
||||
* This returns a promise for an object containing key-value
|
||||
* pairs, where keys are capability names and values are
|
||||
* either:
|
||||
*
|
||||
* * Capability instances
|
||||
* * Capability constructors (which take a domain object
|
||||
* as their argument.)
|
||||
*
|
||||
*
|
||||
* @param {*} model the object model
|
||||
* @returns {Object.<string,function|Capability>} all
|
||||
* capabilities known to be valid for this model, as
|
||||
* key-value pairs
|
||||
*/
|
||||
getCapabilities: getCapabilities
|
||||
};
|
||||
}
|
||||
|
||||
return QueuingPersistenceCapabilityDecorator;
|
||||
}
|
||||
);
|
Reference in New Issue
Block a user