Merge pull request #1445 from nasa/api-updates

Api updates
This commit is contained in:
Andrew Henry 2017-02-21 17:04:45 -08:00 committed by GitHub
commit db33ab143e
10 changed files with 127 additions and 166 deletions

View File

@ -48,9 +48,10 @@ define(
* Decorate PersistenceCapability to queue persistence calls when a * Decorate PersistenceCapability to queue persistence calls when a
* transaction is in progress. * transaction is in progress.
*/ */
TransactionCapabilityDecorator.prototype.getCapabilities = function (model) { TransactionCapabilityDecorator.prototype.getCapabilities = function () {
var self = this, var self = this,
capabilities = this.capabilityService.getCapabilities(model), capabilities = this.capabilityService.getCapabilities
.apply(this.capabilityService, arguments),
persistenceCapability = capabilities.persistence; persistenceCapability = capabilities.persistence;
capabilities.persistence = function (domainObject) { capabilities.persistence = function (domainObject) {

View File

@ -53,10 +53,10 @@ define(
*/ */
function CoreCapabilityProvider(capabilities, $log) { function CoreCapabilityProvider(capabilities, $log) {
// Filter by invoking the capability's appliesTo method // Filter by invoking the capability's appliesTo method
function filterCapabilities(model) { function filterCapabilities(model, id) {
return capabilities.filter(function (capability) { return capabilities.filter(function (capability) {
return capability.appliesTo ? return capability.appliesTo ?
capability.appliesTo(model) : capability.appliesTo(model, id) :
true; true;
}); });
} }
@ -75,8 +75,8 @@ define(
return result; return result;
} }
function getCapabilities(model) { function getCapabilities(model, id) {
return packageCapabilities(filterCapabilities(model)); return packageCapabilities(filterCapabilities(model, id));
} }
return { return {

View File

@ -50,7 +50,7 @@ define(
this.capabilityService = capabilityService; this.capabilityService = capabilityService;
} }
QueuingPersistenceCapabilityDecorator.prototype.getCapabilities = function (model) { QueuingPersistenceCapabilityDecorator.prototype.getCapabilities = function (model, id) {
var capabilityService = this.capabilityService, var capabilityService = this.capabilityService,
persistenceQueue = this.persistenceQueue; persistenceQueue = this.persistenceQueue;
@ -76,7 +76,7 @@ define(
} }
return decoratePersistence( return decoratePersistence(
capabilityService.getCapabilities(model) capabilityService.getCapabilities(model, id)
); );
}; };

View File

@ -32,6 +32,7 @@ define(
mockPersistence, mockPersistence,
mockDomainObject, mockDomainObject,
testModel, testModel,
testId,
decorator; decorator;
beforeEach(function () { beforeEach(function () {
@ -41,6 +42,7 @@ define(
['getCapabilities'] ['getCapabilities']
); );
testModel = { someKey: "some value" }; testModel = { someKey: "some value" };
testId = 'someId';
mockPersistence = jasmine.createSpyObj( mockPersistence = jasmine.createSpyObj(
'persistence', 'persistence',
['persist', 'refresh'] ['persist', 'refresh']
@ -67,9 +69,9 @@ define(
// QueuingPersistenceCapability itself, which has its own tests. // QueuingPersistenceCapability itself, which has its own tests.
it("delegates to its wrapped service", function () { it("delegates to its wrapped service", function () {
decorator.getCapabilities(testModel); decorator.getCapabilities(testModel, testId);
expect(mockCapabilityService.getCapabilities) expect(mockCapabilityService.getCapabilities)
.toHaveBeenCalledWith(testModel); .toHaveBeenCalledWith(testModel, testId);
}); });
it("wraps its persistence capability's constructor", function () { it("wraps its persistence capability's constructor", function () {

View File

@ -38,14 +38,15 @@ define([
} }
APICapabilityDecorator.prototype.getCapabilities = function ( APICapabilityDecorator.prototype.getCapabilities = function (
model model,
id
) { ) {
var capabilities = this.capabilityService.getCapabilities(model); var capabilities = this.capabilityService.getCapabilities(model, id);
if (capabilities.mutation) { if (capabilities.mutation) {
capabilities.mutation = capabilities.mutation =
synchronizeMutationCapability(capabilities.mutation); synchronizeMutationCapability(capabilities.mutation);
} }
if (AlternateCompositionCapability.appliesTo(model)) { if (AlternateCompositionCapability.appliesTo(model, id)) {
capabilities.composition = function (domainObject) { capabilities.composition = function (domainObject) {
return new AlternateCompositionCapability(this.$injector, domainObject); return new AlternateCompositionCapability(this.$injector, domainObject);
}.bind(this); }.bind(this);

View File

@ -21,13 +21,18 @@
*****************************************************************************/ *****************************************************************************/
define([ define([
'../capabilities/AlternateCompositionCapability' '../capabilities/AlternateCompositionCapability',
], function (AlternateCompositionCapability) { '../../api/objects/object-utils'
], function (
AlternateCompositionCapability,
objectUtils
) {
// Present to work around the need for openmct to be used // Present to work around the need for openmct to be used
// from AlternateCompositionCapability.appliesTo, even though it // from AlternateCompositionCapability.appliesTo, even though it
// cannot be injected. // cannot be injected.
function AlternateCompositionInitializer(openmct) { function AlternateCompositionInitializer(openmct) {
AlternateCompositionCapability.appliesTo = function (model) { AlternateCompositionCapability.appliesTo = function (model, id) {
model = objectUtils.toNewFormat(model, id || '');
return !!openmct.composition.get(model); return !!openmct.composition.get(model);
}; };
} }

View File

@ -37,7 +37,7 @@ define(
id = id || identifierService.generate(); id = id || identifierService.generate();
var old_id = model.id; var old_id = model.id;
model.id = id; model.id = id;
var capabilities = capabilityService.getCapabilities(model); var capabilities = capabilityService.getCapabilities(model, id);
model.id = old_id; model.id = old_id;
cacheService.put(id, model); cacheService.put(id, model);
return new DomainObjectImpl(id, model, capabilities); return new DomainObjectImpl(id, model, capabilities);

View File

@ -29,7 +29,8 @@ define([
* @implements module:openmct.TelemetryAPI~TelemetryProvider * @implements module:openmct.TelemetryAPI~TelemetryProvider
* @constructor * @constructor
*/ */
function LegacyTelemetryProvider(instantiate) { function LegacyTelemetryProvider(openmct, instantiate) {
this.telemetryApi = openmct.telemetry;
this.instantiate = instantiate; this.instantiate = instantiate;
} }
@ -44,23 +45,33 @@ define([
utils.makeKeyString(domainObject.identifier)).hasCapability("telemetry"); utils.makeKeyString(domainObject.identifier)).hasCapability("telemetry");
}; };
LegacyTelemetryProvider.prototype.supportsRequest =
LegacyTelemetryProvider.prototype.supportsSubscribe =
LegacyTelemetryProvider.prototype.canProvideTelemetry;
function createDatum(domainObject, metadata, legacySeries, i) { function createDatum(domainObject, metadata, legacySeries, i) {
var datum;
if (legacySeries.getDatum) { if (legacySeries.getDatum) {
return legacySeries.getDatum(i); datum = legacySeries.getDatum(i);
} else {
datum = {};
metadata.valuesForHints(['x']).forEach(function (metadatum) {
datum[metadatum.key] = legacySeries.getDomainValue(i, metadatum.key);
});
metadata.valuesForHints(['y']).forEach(function (metadatum) {
datum[metadatum.key] = legacySeries.getRangeValue(i, metadatum.key);
});
} }
var datum = {};
metadata.domains.reduce(function (d, domain) { /**
d[domain.key] = legacySeries.getDomainValue(i, domain.key); * If telemetry metadata defines a 'name' field, and one is not present
return d; * on the datum, add it.
}, datum); */
if (metadata.value('name') !== undefined && datum.name === undefined) {
metadata.ranges.reduce(function (d, range) { datum.name = domainObject.name;
d[range.key] = legacySeries.getRangeValue(i, range.key); }
return d;
}, datum);
datum.name = domainObject.name;
return datum; return datum;
} }
@ -93,11 +104,12 @@ define([
* telemetry data. * telemetry data.
*/ */
LegacyTelemetryProvider.prototype.request = function (domainObject, request) { LegacyTelemetryProvider.prototype.request = function (domainObject, request) {
var metadata = this.telemetryApi.getMetadata(domainObject);
var oldObject = this.instantiate(utils.toOldFormat(domainObject), utils.makeKeyString(domainObject.identifier)); var oldObject = this.instantiate(utils.toOldFormat(domainObject), utils.makeKeyString(domainObject.identifier));
var capability = oldObject.getCapability("telemetry"); var capability = oldObject.getCapability("telemetry");
return capability.requestData(request).then(function (telemetrySeries) { return capability.requestData(request).then(function (telemetrySeries) {
return Promise.resolve(adaptSeries(domainObject, capability.getMetadata(), telemetrySeries)); return Promise.resolve(adaptSeries(domainObject, metadata, telemetrySeries));
}).catch(function (error) { }).catch(function (error) {
return Promise.reject(error); return Promise.reject(error);
}); });
@ -118,11 +130,12 @@ define([
* @returns {platform|telemetry.TelemetrySubscription|*} * @returns {platform|telemetry.TelemetrySubscription|*}
*/ */
LegacyTelemetryProvider.prototype.subscribe = function (domainObject, callback, request) { LegacyTelemetryProvider.prototype.subscribe = function (domainObject, callback, request) {
var metadata = this.telemetryApi.getMetadata(domainObject);
var oldObject = this.instantiate(utils.toOldFormat(domainObject), utils.makeKeyString(domainObject.identifier)); var oldObject = this.instantiate(utils.toOldFormat(domainObject), utils.makeKeyString(domainObject.identifier));
var capability = oldObject.getCapability("telemetry"); var capability = oldObject.getCapability("telemetry");
function callbackWrapper(series) { function callbackWrapper(series) {
callback(createDatum(domainObject, capability.getMetadata(), series, series.getPointCount() - 1)); callback(createDatum(domainObject, metadata, series, series.getPointCount() - 1));
} }
return capability.subscribe(callbackWrapper, request); return capability.subscribe(callbackWrapper, request);
@ -134,6 +147,10 @@ define([
utils.makeKeyString(domainObject.identifier)); utils.makeKeyString(domainObject.identifier));
var limitEvaluator = oldObject.getCapability("limit"); var limitEvaluator = oldObject.getCapability("limit");
if (!limitEvaluator) {
return;
}
return { return {
evaluate: function (datum, property) { evaluate: function (datum, property) {
return limitEvaluator.evaluate(datum, property.key); return limitEvaluator.evaluate(datum, property.key);
@ -142,10 +159,11 @@ define([
}; };
return function (openmct, instantiate) { return function (openmct, instantiate) {
// Push onto the start of the default providers array so that it's // Legacy provider should always be the fallback.
// always the last resort var provider = new LegacyTelemetryProvider(openmct, instantiate);
openmct.telemetry.defaultProviders.unshift( openmct.telemetry.legacyProvider = provider;
new LegacyTelemetryProvider(instantiate)); openmct.telemetry.requestProviders.push(provider);
openmct.telemetry.subscriptionProviders.push(provider);
}; };
}); });

View File

@ -74,34 +74,6 @@ define([
* @memberof module:openmct.TelemetryAPI~TelemetryFormatter# * @memberof module:openmct.TelemetryAPI~TelemetryFormatter#
*/ */
// format map is a placeholder until we figure out format service.
var FORMAT_MAP = {
generic: function (range) {
return function (datum) {
return datum[range.key];
};
},
enum: function (range) {
var enumMap = _.indexBy(range.enumerations, 'value');
return function (datum) {
try {
return enumMap[datum[range.valueKey]].text;
} catch (e) {
return datum[range.valueKey];
}
};
}
};
FORMAT_MAP.number =
FORMAT_MAP.float =
FORMAT_MAP.integer =
FORMAT_MAP.ascii =
FORMAT_MAP.generic;
/** /**
* Describes a property which would be found in a datum of telemetry * Describes a property which would be found in a datum of telemetry
* associated with a particular domain object. * associated with a particular domain object.
@ -161,8 +133,8 @@ define([
*/ */
function TelemetryAPI(MCT) { function TelemetryAPI(MCT) {
this.MCT = MCT; this.MCT = MCT;
this.providersByStrategy = {}; this.requestProviders = [];
this.defaultProviders = []; this.subscriptionProviders = [];
this.metadataCache = new WeakMap(); this.metadataCache = new WeakMap();
this.formatMapCache = new WeakMap(); this.formatMapCache = new WeakMap();
this.valueFormatterCache = new WeakMap(); this.valueFormatterCache = new WeakMap();
@ -179,9 +151,8 @@ define([
* @memberof module:openmct.TelemetryAPI~TelemetryProvider# * @memberof module:openmct.TelemetryAPI~TelemetryProvider#
*/ */
TelemetryAPI.prototype.canProvideTelemetry = function (domainObject) { TelemetryAPI.prototype.canProvideTelemetry = function (domainObject) {
return this.defaultProviders.some(function (provider) { return !!this.findSubscriptionProvider(domainObject) ||
return provider.canProvideTelemetry(domainObject); !!this.findRequestProvider(domainObject);
});
}; };
/** /**
@ -191,39 +162,38 @@ define([
* @memberof module:openmct.TelemetryAPI# * @memberof module:openmct.TelemetryAPI#
* @param {module:openmct.TelemetryAPI~TelemetryProvider} provider the new * @param {module:openmct.TelemetryAPI~TelemetryProvider} provider the new
* telemetry provider * telemetry provider
* @param {string} [strategy] the request strategy supported by
* this provider. If omitted, this will be used as a
* default provider (when no strategy is requested or no
* matching strategy is found.)
*/ */
TelemetryAPI.prototype.addProvider = function (provider, strategy) { TelemetryAPI.prototype.addProvider = function (provider) {
if (!strategy) { if (provider.supportsRequest) {
this.defaultProviders.push(provider); this.requestProviders.unshift(provider);
} else { }
this.providersByStrategy[strategy] = if (provider.supportsSubscribe) {
this.providersByStrategy[strategy] || []; this.subscriptionProviders.unshift(provider);
this.providersByStrategy[strategy].push(provider);
} }
}; };
/** /**
* @private * @private
*/ */
TelemetryAPI.prototype.findProvider = function (domainObject, strategy) { TelemetryAPI.prototype.findSubscriptionProvider = function (domainObject) {
var args = Array.prototype.slice.apply(arguments);
function supportsDomainObject(provider) { function supportsDomainObject(provider) {
return provider.canProvideTelemetry(domainObject); return provider.supportsSubscribe.apply(provider, args);
} }
if (strategy) { return this.subscriptionProviders.filter(supportsDomainObject)[0];
var eligibleProviders = };
(this.providersByStrategy[strategy] || [])
.filter(supportsDomainObject); /**
if (eligibleProviders.length > 0) { * @private
return eligibleProviders[0]; */
} TelemetryAPI.prototype.findRequestProvider = function (domainObject, options) {
var args = Array.prototype.slice.apply(arguments);
function supportsDomainObject(provider) {
return provider.supportsRequest.apply(provider, args);
} }
return this.defaultProviders.filter(supportsDomainObject)[0]; return this.requestProviders.filter(supportsDomainObject)[0];
}; };
/** /**
@ -242,10 +212,29 @@ define([
* telemetry data * telemetry data
*/ */
TelemetryAPI.prototype.request = function (domainObject, options) { TelemetryAPI.prototype.request = function (domainObject, options) {
var provider = this.findProvider(domainObject, options.strategy); var provider = this.findRequestProvider.apply(this, arguments);
return provider ? return provider.request.apply(provider, arguments);
provider.request(domainObject, options) : };
Promise.reject([]);
/**
* Subscribe to realtime telemetry for a specific domain object.
* The callback will be called whenever data is received from a
* realtime provider.
*
* @method subscribe
* @memberof module:openmct.TelemetryAPI~TelemetryProvider#
* @param {module:openmct.DomainObject} domainObject the object
* which has associated telemetry
* @param {Function} callback the callback to invoke with new data, as
* it becomes available
* @param {module:openmct.TelemetryAPI~TelemetryRequest} options
* options for this request
* @returns {Function} a function which may be called to terminate
* the subscription
*/
TelemetryAPI.prototype.subscribe = function (domainObject, callback, options) {
var provider = this.findSubscriptionProvider.apply(this, arguments);
return provider.subscribe.apply(provider, arguments);
}; };
/** /**
@ -327,53 +316,6 @@ define([
return this.formatMapCache.get(metadata); return this.formatMapCache.get(metadata);
}; };
/**
* Subscribe to realtime telemetry for a specific domain object.
* The callback will be called whenever data is received from a
* realtime provider.
*
* @method subscribe
* @memberof module:openmct.TelemetryAPI~TelemetryProvider#
* @param {module:openmct.DomainObject} domainObject the object
* which has associated telemetry
* @param {Function} callback the callback to invoke with new data, as
* it becomes available
* @param {module:openmct.TelemetryAPI~TelemetryRequest} options
* options for this request
* @returns {Function} a function which may be called to terminate
* the subscription
*/
/**
* Get a list of all telemetry properties defined for this
* domain object.
*
* @param {module:openmct.DomainObject} domainObject the domain
* object for which to request telemetry
* @returns {module:openmct.TelemetryAPI~TelemetryProperty[]}
* telemetry metadata
* @method properties
* @memberof module:openmct.TelemetryAPI~TelemetryProvider#
*/
/**
* Telemetry formatters help you format telemetry values for
* display. Under the covers, they use telemetry metadata to
* interpret your telemetry data, and then they use the format API
* to format that data for display.
*
* This method is optional.
* If a provider does not implement this method, it is presumed
* that all telemetry associated with this domain object can
* be formatted correctly by string coercion.
*
* @param {module:openmct.DomainObject} domainObject the domain
* object for which to format telemetry
* @returns {module:openmct.TelemetryAPI~TelemetryFormatter}
* @method formatter
* @memberof module:openmct.TelemetryAPI~TelemetryProvider#
*/
/** /**
* Get a limit evaluator for this domain object. * Get a limit evaluator for this domain object.
* Limit Evaluators help you evaluate limit and alarm status of individual telemetry datums for display purposes without having to interact directly with the Limit API. * Limit Evaluators help you evaluate limit and alarm status of individual telemetry datums for display purposes without having to interact directly with the Limit API.
@ -388,19 +330,9 @@ define([
* @method limitEvaluator * @method limitEvaluator
* @memberof module:openmct.TelemetryAPI~TelemetryProvider# * @memberof module:openmct.TelemetryAPI~TelemetryProvider#
*/ */
_.forEach({ TelemetryAPI.prototype.limitEvaluator = function () {
subscribe: undefined, return this.legacyProvider.limitEvaluator.apply(this.legacyProvider, arguments);
properties: [], };
formatter: undefined,
limitEvaluator: undefined
}, function (defaultValue, method) {
TelemetryAPI.prototype[method] = function (domainObject) {
var provider = this.findProvider(domainObject);
return provider ?
provider[method].apply(provider, arguments) :
defaultValue;
};
});
return TelemetryAPI; return TelemetryAPI;
}); });

View File

@ -28,6 +28,18 @@ define([
// TODO: needs reference to formatService; // TODO: needs reference to formatService;
function TelemetryValueFormatter(valueMetadata, formatService) { function TelemetryValueFormatter(valueMetadata, formatService) {
var numberFormatter = {
parse: function (x) {
return Number(x);
},
format: function (x) {
return x;
},
validate: function (x) {
return true;
}
};
this.valueMetadata = valueMetadata; this.valueMetadata = valueMetadata;
this.parseCache = new WeakMap(); this.parseCache = new WeakMap();
this.formatCache = new WeakMap(); this.formatCache = new WeakMap();
@ -36,17 +48,7 @@ define([
.getFormat(valueMetadata.format, valueMetadata); .getFormat(valueMetadata.format, valueMetadata);
} catch (e) { } catch (e) {
// TODO: Better formatting // TODO: Better formatting
this.formatter = { this.formatter = numberFormatter;
parse: function (x) {
return Number(x);
},
format: function (x) {
return x;
},
validate: function (x) {
return true;
}
};
} }
if (valueMetadata.type === 'enum') { if (valueMetadata.type === 'enum') {