mirror of
https://github.com/nasa/openmct.git
synced 2025-06-22 17:08:57 +00:00
Add object interceptor API to allow missing model and missing my-items handling (#3522)
* Extends Object API to allow adding interceptors Co-authored-by: Andrew Henry <akhenry@gmail.com>
This commit is contained in:
66
src/api/objects/InterceptorRegistry.js
Normal file
66
src/api/objects/InterceptorRegistry.js
Normal file
@ -0,0 +1,66 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
export default class InterceptorRegistry {
|
||||
/**
|
||||
* A InterceptorRegistry maintains the definitions for different interceptors that may be invoked on domain objects.
|
||||
* @interface InterceptorRegistry
|
||||
* @memberof module:openmct
|
||||
*/
|
||||
constructor() {
|
||||
this.interceptors = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @interface InterceptorDef
|
||||
* @property {function} appliesTo function that determines if this interceptor should be called for the given identifier/object
|
||||
* @property {function} invoke function that transforms the provided domain object and returns the transformed domain object
|
||||
* @property {function} priority the priority for this interceptor. A higher number returned has more weight than a lower number
|
||||
* @memberof module:openmct InterceptorRegistry#
|
||||
*/
|
||||
|
||||
/**
|
||||
* Register a new object interceptor.
|
||||
*
|
||||
* @param {module:openmct.InterceptorDef} interceptorDef the interceptor to add
|
||||
* @method addInterceptor
|
||||
* @memberof module:openmct.InterceptorRegistry#
|
||||
*/
|
||||
addInterceptor(interceptorDef) {
|
||||
//TODO: sort by priority
|
||||
this.interceptors.push(interceptorDef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all interceptors applicable to a domain object.
|
||||
* @method getInterceptors
|
||||
* @returns [module:openmct.InterceptorDef] the registered interceptors for this identifier/object
|
||||
* @memberof module:openmct.InterceptorRegistry#
|
||||
*/
|
||||
getInterceptors(identifier, object) {
|
||||
return this.interceptors.filter(interceptor => {
|
||||
return typeof interceptor.appliesTo === 'function'
|
||||
&& interceptor.appliesTo(identifier, object);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
0
src/api/objects/InterceptorRegistrySpec.js
Normal file
0
src/api/objects/InterceptorRegistrySpec.js
Normal file
@ -26,6 +26,7 @@ define([
|
||||
'./MutableObject',
|
||||
'./RootRegistry',
|
||||
'./RootObjectProvider',
|
||||
'./InterceptorRegistry',
|
||||
'EventEmitter'
|
||||
], function (
|
||||
_,
|
||||
@ -33,6 +34,7 @@ define([
|
||||
MutableObject,
|
||||
RootRegistry,
|
||||
RootObjectProvider,
|
||||
InterceptorRegistry,
|
||||
EventEmitter
|
||||
) {
|
||||
|
||||
@ -48,6 +50,7 @@ define([
|
||||
this.rootRegistry = new RootRegistry();
|
||||
this.rootProvider = new RootObjectProvider.default(this.rootRegistry);
|
||||
this.cache = {};
|
||||
this.interceptorRegistry = new InterceptorRegistry.default();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -177,6 +180,10 @@ define([
|
||||
|
||||
return objectPromise.then(result => {
|
||||
delete this.cache[keystring];
|
||||
const interceptors = this.listGetInterceptors(identifier, result);
|
||||
interceptors.forEach(interceptor => {
|
||||
result = interceptor.invoke(identifier, result);
|
||||
});
|
||||
|
||||
return result;
|
||||
});
|
||||
@ -312,6 +319,27 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Register an object interceptor that transforms a domain object requested via module:openmct.ObjectAPI.get
|
||||
* The domain object will be transformed after it is retrieved from the persistence store
|
||||
* The domain object will be transformed only if the interceptor is applicable to that domain object as defined by the InterceptorDef
|
||||
*
|
||||
* @param {module:openmct.InterceptorDef} interceptorDef the interceptor definition to add
|
||||
* @method addGetInterceptor
|
||||
* @memberof module:openmct.InterceptorRegistry#
|
||||
*/
|
||||
ObjectAPI.prototype.addGetInterceptor = function (interceptorDef) {
|
||||
this.interceptorRegistry.addInterceptor(interceptorDef);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the interceptors for a given domain object.
|
||||
* @private
|
||||
*/
|
||||
ObjectAPI.prototype.listGetInterceptors = function (identifier, object) {
|
||||
return this.interceptorRegistry.getInterceptors(identifier, object);
|
||||
};
|
||||
|
||||
/**
|
||||
* Uniquely identifies a domain object.
|
||||
*
|
||||
|
@ -63,12 +63,51 @@ describe("The Object API", () => {
|
||||
describe("The get function", () => {
|
||||
describe("when a provider is available", () => {
|
||||
let mockProvider;
|
||||
let mockInterceptor;
|
||||
let anotherMockInterceptor;
|
||||
let notApplicableMockInterceptor;
|
||||
beforeEach(() => {
|
||||
mockProvider = jasmine.createSpyObj("mock provider", [
|
||||
"get"
|
||||
]);
|
||||
mockProvider.get.and.returnValue(Promise.resolve(mockDomainObject));
|
||||
|
||||
mockInterceptor = jasmine.createSpyObj("mock interceptor", [
|
||||
"appliesTo",
|
||||
"invoke"
|
||||
]);
|
||||
mockInterceptor.appliesTo.and.returnValue(true);
|
||||
mockInterceptor.invoke.and.callFake((identifier, object) => {
|
||||
return Object.assign({
|
||||
changed: true
|
||||
}, object);
|
||||
});
|
||||
|
||||
anotherMockInterceptor = jasmine.createSpyObj("another mock interceptor", [
|
||||
"appliesTo",
|
||||
"invoke"
|
||||
]);
|
||||
anotherMockInterceptor.appliesTo.and.returnValue(true);
|
||||
anotherMockInterceptor.invoke.and.callFake((identifier, object) => {
|
||||
return Object.assign({
|
||||
alsoChanged: true
|
||||
}, object);
|
||||
});
|
||||
|
||||
notApplicableMockInterceptor = jasmine.createSpyObj("not applicable mock interceptor", [
|
||||
"appliesTo",
|
||||
"invoke"
|
||||
]);
|
||||
notApplicableMockInterceptor.appliesTo.and.returnValue(false);
|
||||
notApplicableMockInterceptor.invoke.and.callFake((identifier, object) => {
|
||||
return Object.assign({
|
||||
shouldNotBeChanged: true
|
||||
}, object);
|
||||
});
|
||||
objectAPI.addProvider(TEST_NAMESPACE, mockProvider);
|
||||
objectAPI.addGetInterceptor(mockInterceptor);
|
||||
objectAPI.addGetInterceptor(anotherMockInterceptor);
|
||||
objectAPI.addGetInterceptor(notApplicableMockInterceptor);
|
||||
});
|
||||
|
||||
it("Caches multiple requests for the same object", () => {
|
||||
@ -78,6 +117,15 @@ describe("The Object API", () => {
|
||||
objectAPI.get(mockDomainObject.identifier);
|
||||
expect(mockProvider.get.calls.count()).toBe(1);
|
||||
});
|
||||
|
||||
it("applies any applicable interceptors", () => {
|
||||
expect(mockDomainObject.changed).toBeUndefined();
|
||||
objectAPI.get(mockDomainObject.identifier).then((object) => {
|
||||
expect(object.changed).toBeTrue();
|
||||
expect(object.alsoChanged).toBeTrue();
|
||||
expect(object.shouldNotBeChanged).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user