Compare commits
	
		
			5 Commits
		
	
	
		
			reorder-in
			...
			open245
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					ab4d73dba6 | ||
| 
						 | 
					92755f040c | ||
| 
						 | 
					551f95363f | ||
| 
						 | 
					7f5ce2e712 | ||
| 
						 | 
					e0c5cb099d | 
							
								
								
									
										32
									
								
								platform/persistence/multi/bundle.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								platform/persistence/multi/bundle.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
{
 | 
			
		||||
    "extensions": {
 | 
			
		||||
        "components": [
 | 
			
		||||
            {
 | 
			
		||||
                "type": "decorator",
 | 
			
		||||
                "provides": "persistenceService",
 | 
			
		||||
                "implementation": "MultiPersistenceDecorator.js",
 | 
			
		||||
                "depends": [
 | 
			
		||||
                    "persistenceService",
 | 
			
		||||
                    "$q",
 | 
			
		||||
                    "MULTI_PERSISTENCE_SPACE_MAPPINGS",
 | 
			
		||||
                    "MULTI_PERSISTENCE_DEFAULT_SPACE",
 | 
			
		||||
                    "PERSISTENCE_SPACE"
 | 
			
		||||
                ]
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "constants": [
 | 
			
		||||
            {
 | 
			
		||||
                "key": "MULTI_PERSISTENCE_SPACE_MAPPINGS",
 | 
			
		||||
                "value": {},
 | 
			
		||||
                "priority": "fallback",
 | 
			
		||||
                "comment": "Maps identifiers to persistence spaces (statically.)"
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "key": "MULTI_PERSISTENCE_DEFAULT_SPACE",
 | 
			
		||||
                "value": "mct",
 | 
			
		||||
                "priority": "fallback",
 | 
			
		||||
                "comment": "Should be overridden with a reasonable default."
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										73
									
								
								platform/persistence/multi/src/AsyncMutex.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								platform/persistence/multi/src/AsyncMutex.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web 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 Web 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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*global define,Promise*/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
        'use strict';
 | 
			
		||||
 | 
			
		||||
        function AsyncMutex($q) {
 | 
			
		||||
            this.queue = [];
 | 
			
		||||
            this.$q = $q;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        AsyncMutex.prototype.acquire = function (callback) {
 | 
			
		||||
            var deferred = this.$q.defer(),
 | 
			
		||||
                queue = this.queue;
 | 
			
		||||
 | 
			
		||||
            function advance() {
 | 
			
		||||
                if (queue.length > 0) {
 | 
			
		||||
                    queue.shift()();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function release(result) {
 | 
			
		||||
                deferred.resolve(result);
 | 
			
		||||
                advance();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function next() {
 | 
			
		||||
                try {
 | 
			
		||||
                    callback(release);
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
                    deferred.reject(e);
 | 
			
		||||
                    advance();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            queue.push(next);
 | 
			
		||||
            if (queue.length === 1) {
 | 
			
		||||
                advance();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return deferred.promise;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        AsyncMutex.prototype.use = function (callback) {
 | 
			
		||||
            return this.acquire(function (release) {
 | 
			
		||||
                release(callback);
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										125
									
								
								platform/persistence/multi/src/MultiPersistenceDecorator.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								platform/persistence/multi/src/MultiPersistenceDecorator.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,125 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web 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 Web 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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*global define*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This bundle implements a persistence service which uses ElasticSearch to
 | 
			
		||||
 * store documents.
 | 
			
		||||
 * @namespace platform/persistence/elastic
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ['./PersistenceTable'],
 | 
			
		||||
    function (PersistenceTable) {
 | 
			
		||||
        'use strict';
 | 
			
		||||
 | 
			
		||||
        function MultiPersistenceDecorator(
 | 
			
		||||
            persistenceService,
 | 
			
		||||
            $q,
 | 
			
		||||
            spaceMappings,
 | 
			
		||||
            defaultSpace,
 | 
			
		||||
            spaceToRemap
 | 
			
		||||
        ) {
 | 
			
		||||
            this.table = new PersistenceTable(
 | 
			
		||||
                persistenceService,
 | 
			
		||||
                $q,
 | 
			
		||||
                spaceMappings,
 | 
			
		||||
                defaultSpace
 | 
			
		||||
            );
 | 
			
		||||
            this.spaceToRemap = spaceToRemap;
 | 
			
		||||
            this.persistenceService = persistenceService;
 | 
			
		||||
            this.$q = $q;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Public API
 | 
			
		||||
        MultiPersistenceDecorator.prototype.listSpaces = function () {
 | 
			
		||||
            var spaceToRemap = this.spaceToRemap,
 | 
			
		||||
                mappedSpaces = this.table.getSpaces();
 | 
			
		||||
 | 
			
		||||
            return this.persistenceService.listSpaces.then(function (spaces) {
 | 
			
		||||
                // Hide the existence of alternate spaces; make them
 | 
			
		||||
                // appear as the one global space for storing domain objects.
 | 
			
		||||
                return spaces.filter(function (space) {
 | 
			
		||||
                    return mappedSpaces.indexOf(space) === -1;
 | 
			
		||||
                }).concat([spaceToRemap]);
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        MultiPersistenceDecorator.prototype.listObjects = function (space) {
 | 
			
		||||
            var persistenceService = this.persistenceService;
 | 
			
		||||
            if (space === this.spaceToRemap) {
 | 
			
		||||
                return this.$q.all(this.mappedSpaces.map(function (s) {
 | 
			
		||||
                    return persistenceService.listObjects(s);
 | 
			
		||||
                })).then(function (lists) {
 | 
			
		||||
                    return lists.reduce(function (a, b) {
 | 
			
		||||
                        return a.concat(b);
 | 
			
		||||
                    }, []);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            return persistenceService.listObjects(space);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        MultiPersistenceDecorator.prototype.createObject = function (space, key, value) {
 | 
			
		||||
            var persistenceService = this.persistenceService,
 | 
			
		||||
                table = this.table;
 | 
			
		||||
            if (space === this.spaceToRemap) {
 | 
			
		||||
                return table.getSpace(value.location).then(function (s) {
 | 
			
		||||
                    return table.setSpace(key, s).then(function () {
 | 
			
		||||
                        return persistenceService.createObject(s, key, value);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            return persistenceService.createObject(space, key, value);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        MultiPersistenceDecorator.prototype.readObject = function (space, key) {
 | 
			
		||||
            var persistenceService = this.persistenceService;
 | 
			
		||||
            if (space === this.spaceToRemap) {
 | 
			
		||||
                return this.table.getSpace(key).then(function (s) {
 | 
			
		||||
                    return persistenceService.readObject(s, key);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            return persistenceService.readObject(space, key);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        MultiPersistenceDecorator.prototype.updateObject = function (space, key, value) {
 | 
			
		||||
            var persistenceService = this.persistenceService,
 | 
			
		||||
                table = this.table,
 | 
			
		||||
                self = this;
 | 
			
		||||
            if (space === this.spaceToRemap) {
 | 
			
		||||
                return this.table.getSpace(key).then(function (currentSpace) {
 | 
			
		||||
                    return this.table.getSpace(value.location).then(function (newSpace) {
 | 
			
		||||
                        // TODO: Also move children when space change happens?
 | 
			
		||||
                        return (newSpace === currentSpace) ?
 | 
			
		||||
                                persistenceService.updateObject(newSpace, key, value) :
 | 
			
		||||
                                self.createObject(space, key, value);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            return persistenceService.createObject(space, key, value);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        MultiPersistenceDecorator.prototype.deleteObject = function (space, key, value) {
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return MultiPersistenceDecorator;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										77
									
								
								platform/persistence/multi/src/PersistenceTable.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								platform/persistence/multi/src/PersistenceTable.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web 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 Web 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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*global define,Promise*/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ['./AsyncMutex', './PersistenceTableInitializer'],
 | 
			
		||||
    function (AsyncMutex, PersistenceTableInitializer) {
 | 
			
		||||
        'use strict';
 | 
			
		||||
 | 
			
		||||
        function PersistenceTable(
 | 
			
		||||
            persistenceService,
 | 
			
		||||
            $q,
 | 
			
		||||
            spaceMappings,
 | 
			
		||||
            defaultSpace
 | 
			
		||||
        ) {
 | 
			
		||||
            var spaces = Object.keys(spaceMappings).map(function (id) {
 | 
			
		||||
                    return spaceMappings[id];
 | 
			
		||||
                }).sort().filter(function (item, i, arr) {
 | 
			
		||||
                    return i === 0 || arr[i - 1] !== item;
 | 
			
		||||
                }),
 | 
			
		||||
                initializer =
 | 
			
		||||
                    new PersistenceTableInitializer($q, persistenceService),
 | 
			
		||||
                self = this;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            this.mutex = new AsyncMutex($q);
 | 
			
		||||
            this.$q = $q;
 | 
			
		||||
            this.staticSpaceMappings = spaceMappings;
 | 
			
		||||
            this.defaultSpace = defaultSpace;
 | 
			
		||||
            this.spaces = spaces;
 | 
			
		||||
 | 
			
		||||
            this.mutex.acquire(function (release) {
 | 
			
		||||
                initializer.initialTable(spaces).then(function (table) {
 | 
			
		||||
                    self.observedSpaceMappings = table;
 | 
			
		||||
                }).then(release);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        PersistenceTable.prototype.setSpace = function (id, space) {
 | 
			
		||||
            var mappings = this.observedSpaceMappings;
 | 
			
		||||
            return this.mutex.use(function () {
 | 
			
		||||
                this.observedSpaceMappings[id] = space;
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PersistenceTable.prototype.getSpace = function (id) {
 | 
			
		||||
            var self = this;
 | 
			
		||||
            return this.mutex.use(function () {
 | 
			
		||||
                return self.staticSpaceMappings[id] ||
 | 
			
		||||
                    self.observedSpaceMappings[id];
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PersistenceTable.prototype.getSpaces = function () {
 | 
			
		||||
            return this.spaces;
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -0,0 +1,77 @@
 | 
			
		||||
/*global define*/
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
        'use strict';
 | 
			
		||||
 | 
			
		||||
        function PersistenceTableInitializer($q, persistenceService) {
 | 
			
		||||
            this.$q = $q;
 | 
			
		||||
            this.persistenceService = persistenceService;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        PersistenceTableInitializer.prototype.initialTable = function (spaces) {
 | 
			
		||||
            var persistenceService = this.persistenceService,
 | 
			
		||||
                $q = this.$q,
 | 
			
		||||
                unreconciledSpaceMappings = {},
 | 
			
		||||
                reconciledSpaceMappings = {};
 | 
			
		||||
 | 
			
		||||
            function initializeSpace(space) {
 | 
			
		||||
                return persistenceService.listObjects().then(function (ids) {
 | 
			
		||||
                    ids.forEach(function (id) {
 | 
			
		||||
                        unreconciledSpaceMappings[id] =
 | 
			
		||||
                            unreconciledSpaceMappings[id] || [];
 | 
			
		||||
                        unreconciledSpaceMappings[id].push(space);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function choose(models) {
 | 
			
		||||
                var index = 0,
 | 
			
		||||
                    greatest = Number.NEGATIVE_INFINITY;
 | 
			
		||||
 | 
			
		||||
                models.forEach(function (model, i) {
 | 
			
		||||
                    if (model.persisted !== undefined &&
 | 
			
		||||
                            model.persisted > greatest) {
 | 
			
		||||
                        greatest = model.persisted;
 | 
			
		||||
                        index = i;
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return index;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function reconcileConflict(id) {
 | 
			
		||||
                var candidateSpaces = unreconciledSpaceMappings[id];
 | 
			
		||||
                return $q.all(candidateSpaces.map(function (space) {
 | 
			
		||||
                    return persistenceService.readObject(space, id);
 | 
			
		||||
                })).then(choose).then(function (index) {
 | 
			
		||||
                    reconciledSpaceMappings[id] = candidateSpaces[index];
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function reconcileConflicts() {
 | 
			
		||||
                var toReconcile = [];
 | 
			
		||||
                Object.keys(unreconciledSpaceMappings).forEach(function (id) {
 | 
			
		||||
                    if (unreconciledSpaceMappings[id].length > 1) {
 | 
			
		||||
                        toReconcile.push(id);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        reconciledSpaceMappings[id] =
 | 
			
		||||
                            unreconciledSpaceMappings[id][0];
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
                return $q.all(toReconcile.map(reconcileConflict));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function giveResult() {
 | 
			
		||||
                return reconciledSpaceMappings;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return $q.all(spaces.map(initializeSpace))
 | 
			
		||||
                .then(reconcileConflicts)
 | 
			
		||||
                .then(giveResult);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
		Reference in New Issue
	
	Block a user