diff --git a/platform/commonUI/edit/src/capabilities/TransactionCapabilityDecorator.js b/platform/commonUI/edit/src/capabilities/TransactionCapabilityDecorator.js index 344f56435b..d93ccfb128 100644 --- a/platform/commonUI/edit/src/capabilities/TransactionCapabilityDecorator.js +++ b/platform/commonUI/edit/src/capabilities/TransactionCapabilityDecorator.js @@ -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) { diff --git a/platform/core/src/capabilities/CoreCapabilityProvider.js b/platform/core/src/capabilities/CoreCapabilityProvider.js index 412b7a57a2..c2dd75233d 100644 --- a/platform/core/src/capabilities/CoreCapabilityProvider.js +++ b/platform/core/src/capabilities/CoreCapabilityProvider.js @@ -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 { diff --git a/platform/persistence/queue/src/QueuingPersistenceCapabilityDecorator.js b/platform/persistence/queue/src/QueuingPersistenceCapabilityDecorator.js index 904ed66f47..66213e59ce 100644 --- a/platform/persistence/queue/src/QueuingPersistenceCapabilityDecorator.js +++ b/platform/persistence/queue/src/QueuingPersistenceCapabilityDecorator.js @@ -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) ); }; diff --git a/platform/persistence/queue/test/QueuingPersistenceCapabilityDecoratorSpec.js b/platform/persistence/queue/test/QueuingPersistenceCapabilityDecoratorSpec.js index 57edcc70c8..fbdaa69304 100644 --- a/platform/persistence/queue/test/QueuingPersistenceCapabilityDecoratorSpec.js +++ b/platform/persistence/queue/test/QueuingPersistenceCapabilityDecoratorSpec.js @@ -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 () { diff --git a/src/adapter/capabilities/APICapabilityDecorator.js b/src/adapter/capabilities/APICapabilityDecorator.js index 01bd6a32ef..8b964f553f 100644 --- a/src/adapter/capabilities/APICapabilityDecorator.js +++ b/src/adapter/capabilities/APICapabilityDecorator.js @@ -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); diff --git a/src/adapter/runs/AlternateCompositionInitializer.js b/src/adapter/runs/AlternateCompositionInitializer.js index 2129086b8c..ac815e48aa 100644 --- a/src/adapter/runs/AlternateCompositionInitializer.js +++ b/src/adapter/runs/AlternateCompositionInitializer.js @@ -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); }; } diff --git a/src/adapter/services/Instantiate.js b/src/adapter/services/Instantiate.js index 3b4c190705..21c6f9742a 100644 --- a/src/adapter/services/Instantiate.js +++ b/src/adapter/services/Instantiate.js @@ -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); diff --git a/src/api/telemetry/LegacyTelemetryProvider.js b/src/api/telemetry/LegacyTelemetryProvider.js index f76fe99d10..3721e5af08 100644 --- a/src/api/telemetry/LegacyTelemetryProvider.js +++ b/src/api/telemetry/LegacyTelemetryProvider.js @@ -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); }; }); diff --git a/src/api/telemetry/TelemetryAPI.js b/src/api/telemetry/TelemetryAPI.js index a7b533f25d..d4750b1251 100644 --- a/src/api/telemetry/TelemetryAPI.js +++ b/src/api/telemetry/TelemetryAPI.js @@ -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; }); diff --git a/src/api/telemetry/TelemetryValueFormatter.js b/src/api/telemetry/TelemetryValueFormatter.js index 801aee1176..a5e8cb8720 100644 --- a/src/api/telemetry/TelemetryValueFormatter.js +++ b/src/api/telemetry/TelemetryValueFormatter.js @@ -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') {