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
* transaction is in progress.
*/
TransactionCapabilityDecorator.prototype.getCapabilities = function (model) {
TransactionCapabilityDecorator.prototype.getCapabilities = function () {
var self = this,
capabilities = this.capabilityService.getCapabilities(model),
capabilities = this.capabilityService.getCapabilities
.apply(this.capabilityService, arguments),
persistenceCapability = capabilities.persistence;
capabilities.persistence = function (domainObject) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -74,34 +74,6 @@ define([
* @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
* associated with a particular domain object.
@ -161,8 +133,8 @@ define([
*/
function TelemetryAPI(MCT) {
this.MCT = MCT;
this.providersByStrategy = {};
this.defaultProviders = [];
this.requestProviders = [];
this.subscriptionProviders = [];
this.metadataCache = new WeakMap();
this.formatMapCache = new WeakMap();
this.valueFormatterCache = new WeakMap();
@ -179,9 +151,8 @@ define([
* @memberof module:openmct.TelemetryAPI~TelemetryProvider#
*/
TelemetryAPI.prototype.canProvideTelemetry = function (domainObject) {
return this.defaultProviders.some(function (provider) {
return provider.canProvideTelemetry(domainObject);
});
return !!this.findSubscriptionProvider(domainObject) ||
!!this.findRequestProvider(domainObject);
};
/**
@ -191,39 +162,38 @@ define([
* @memberof module:openmct.TelemetryAPI#
* @param {module:openmct.TelemetryAPI~TelemetryProvider} provider the new
* 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) {
if (!strategy) {
this.defaultProviders.push(provider);
} else {
this.providersByStrategy[strategy] =
this.providersByStrategy[strategy] || [];
this.providersByStrategy[strategy].push(provider);
TelemetryAPI.prototype.addProvider = function (provider) {
if (provider.supportsRequest) {
this.requestProviders.unshift(provider);
}
if (provider.supportsSubscribe) {
this.subscriptionProviders.unshift(provider);
}
};
/**
* @private
*/
TelemetryAPI.prototype.findProvider = function (domainObject, strategy) {
TelemetryAPI.prototype.findSubscriptionProvider = function (domainObject) {
var args = Array.prototype.slice.apply(arguments);
function supportsDomainObject(provider) {
return provider.canProvideTelemetry(domainObject);
return provider.supportsSubscribe.apply(provider, args);
}
if (strategy) {
var eligibleProviders =
(this.providersByStrategy[strategy] || [])
.filter(supportsDomainObject);
if (eligibleProviders.length > 0) {
return eligibleProviders[0];
}
return this.subscriptionProviders.filter(supportsDomainObject)[0];
};
/**
* @private
*/
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
*/
TelemetryAPI.prototype.request = function (domainObject, options) {
var provider = this.findProvider(domainObject, options.strategy);
return provider ?
provider.request(domainObject, options) :
Promise.reject([]);
var provider = this.findRequestProvider.apply(this, arguments);
return provider.request.apply(provider, arguments);
};
/**
* 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);
};
/**
* 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.
* 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
* @memberof module:openmct.TelemetryAPI~TelemetryProvider#
*/
_.forEach({
subscribe: undefined,
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;
};
});
TelemetryAPI.prototype.limitEvaluator = function () {
return this.legacyProvider.limitEvaluator.apply(this.legacyProvider, arguments);
};
return TelemetryAPI;
});

View File

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