webgme-engine
Version:
WebGME server and Client API without a GUI
696 lines (560 loc) • 26.1 kB
JavaScript
/*globals define*/
/*eslint-env node, browser*/
/**
* @author kecso / https://github.com/kecso
*/
define([
'common/core/CoreAssert',
'common/core/constants',
'common/core/tasync'
], function (ASSERT, CONSTANTS, TASYNC) {
'use strict';
function SetCore(innerCore, options) {
ASSERT(typeof options === 'object');
ASSERT(typeof options.globConf === 'object');
ASSERT(typeof options.logger !== 'undefined');
var logger = options.logger,
self = this,
key;
for (key in innerCore) {
this[key] = innerCore[key];
}
logger.debug('initialized SetCore');
//<editor-fold=Helper Functions>
function setModified(node) {
innerCore.setRegistry(node, CONSTANTS.SET_MODIFIED_REGISTRY,
(innerCore.getRegistry(node, CONSTANTS.SET_MODIFIED_REGISTRY) || 0) + 1);
}
function getSetNodeByName(node, setName) {
return innerCore.getChild(innerCore.getChild(node, CONSTANTS.ALL_SETS_PROPERTY), setName);
}
function getSetInfoByName(node, setName) {
ASSERT(typeof setName === 'string');
var setsInfo = innerCore.getProperty(node, CONSTANTS.ALL_SETS_PROPERTY);
return setsInfo && setsInfo[setName];
}
function getRelativeMemberPath(ownerPath, memberPath) {
if (self.isPathInSubTree(memberPath, ownerPath)) {
return self.getCommonPathPrefixData(ownerPath, memberPath).second;
}
return null;
}
function getOwnMemberRelId(node, setName, memberPath) {
var setInfo,
keys,
i;
setInfo = getSetInfoByName(node, setName);
if (setInfo) {
keys = self.getRawKeys(setInfo, self.isValidRelid);
for (i = 0; i < keys.length; i += 1) {
if (innerCore.getPointerPathFrom(node,
'/' + CONSTANTS.ALL_SETS_PROPERTY + '/' + setName + '/' + keys[i],
CONSTANTS.MEMBER_RELATION) === memberPath) {
return keys[i];
}
}
}
return null;
}
function getMemberRelId(node, setName, memberPath) {
var relid = null,
relativeMemberPath = null;
do {
if (relativeMemberPath !== null) {
relid = getOwnMemberRelId(node, setName, self.getPath(node) + relativeMemberPath);
if (relid) {
return relid;
}
}
relid = getOwnMemberRelId(node, setName, memberPath);
if (relid) {
return relid;
}
typeof memberPath === 'string' ?
relativeMemberPath = getRelativeMemberPath(self.getPath(node), memberPath) : null;
node = self.getBase(node);
} while (node);
return relid;
}
function getSetMemberNode(node, setName, memberPath) {
var memberRelId = getMemberRelId(node, setName, memberPath);
return typeof memberRelId === 'string' && innerCore.getChild(getSetNodeByName(node, setName), memberRelId);
}
function getOwnSetMemberNode(node, setName, memberPath) {
var memberRelId = getOwnMemberRelId(node, setName, memberPath);
return typeof memberRelId === 'string' && innerCore.getChild(getSetNodeByName(node, setName), memberRelId);
}
function collectOwnSetNames(node) {
var sets = [],
setsInfo,
keys,
i;
setsInfo = self.getProperty(node, CONSTANTS.ALL_SETS_PROPERTY);
if (setsInfo &&
setsInfo[CONSTANTS.OVERLAYS_PROPERTY] &&
setsInfo[CONSTANTS.OVERLAYS_PROPERTY]['']) {
keys = Object.keys(setsInfo[CONSTANTS.OVERLAYS_PROPERTY]['']);
for (i = 0; i < keys.length; i += 1) {
if (keys[i] !== CONSTANTS.MUTABLE_PROPERTY && sets.indexOf(keys[i]) === -1) {
sets.push(keys[i]);
}
}
}
return sets;
}
function collectSetNames(node) {
var sets = [],
keys,
i;
do {
keys = collectOwnSetNames(node);
for (i = 0; i < keys.length; i += 1) {
if (sets.indexOf(keys[i]) === -1) {
sets.push(keys[i]);
}
}
node = self.getBase(node);
} while (node);
return sets;
}
function hasOwnSet(node, setName) {
ASSERT(typeof setName === 'string');
var setsInfo = self.getProperty(node, CONSTANTS.ALL_SETS_PROPERTY);
if (setsInfo &&
setsInfo[CONSTANTS.OVERLAYS_PROPERTY] &&
setsInfo[CONSTANTS.OVERLAYS_PROPERTY][''] &&
setsInfo[CONSTANTS.OVERLAYS_PROPERTY][''][setName]) {
return true;
}
return false;
}
function hasSet(node, setName) {
do {
if (hasOwnSet(node, setName)) {
return true;
}
node = self.getBase(node);
} while (node);
return false;
}
function collectInternalMemberRelids(node, setName) {
var setInfo,
relids = [],
keys,
i;
do {
setInfo = getSetInfoByName(node, setName);
if (setInfo) {
keys = self.getRawKeys(setInfo, self.isValidRelid);
for (i = 0; i < keys.length; i += 1) {
if (relids.indexOf(keys[i]) === -1) {
relids.push(keys[i]);
}
}
}
node = self.getBase(node);
} while (node);
return relids;
}
function getContainerNodePath(node) {
var ownPath = self.getPath(node);
return ownPath.substring(0, ownPath.indexOf('/_'));
}
function collectMemberPath(node, setName, innerRelid) {
var source = '/' + CONSTANTS.ALL_SETS_PROPERTY + '/' + setName + '/' + innerRelid,
path,
tempPath;
do {
tempPath = innerCore.getPointerPathFrom(node, source, CONSTANTS.MEMBER_RELATION);
if (tempPath !== undefined) {
path = tempPath;
if (path !== getContainerNodePath(node)) {
break;
}
}
node = self.getBase(node);
} while (node);
return path;
}
function getPropertyCollectionInfo(node, propertyCollectionName, setName, memberPath) {
var setInfo = getSetInfoByName(node, setName),
propertyCollectionInfo,
relid;
if (setInfo) {
if (typeof memberPath === 'string') {
relid = getOwnMemberRelId(node, setName, memberPath);
propertyCollectionInfo = relid && setInfo[relid] && setInfo[relid][propertyCollectionName];
} else {
propertyCollectionInfo = setInfo[propertyCollectionName];
}
}
return propertyCollectionInfo;
}
function collectOwnPropertyNames(node, propertyCollectionName, setName, memberPath) {
var propertyCollectionInfo = getPropertyCollectionInfo(node, propertyCollectionName, setName, memberPath);
return propertyCollectionInfo ? innerCore.getRawKeys(propertyCollectionInfo) : [];
}
function collectPropertyNames(node, propertyCollectionName, setName, memberPath) {
var names = [],
keys,
relativeMemberPath = null,
i;
do {
if (relativeMemberPath !== null) {
keys = collectOwnPropertyNames(node, propertyCollectionName, setName,
self.getPath(node) + relativeMemberPath);
if (keys.length === 0) {
keys = collectOwnPropertyNames(node, propertyCollectionName, setName, memberPath);
} else {
memberPath = self.getPath(node) + relativeMemberPath;
}
} else {
keys = collectOwnPropertyNames(node, propertyCollectionName, setName, memberPath);
}
for (i = 0; i < keys.length; i += 1) {
if (names.indexOf(keys[i]) === -1) {
names.push(keys[i]);
}
}
relativeMemberPath = typeof memberPath === 'string' ?
getRelativeMemberPath(self.getPath(node), memberPath) : null;
node = self.getBase(node);
} while (node);
return names;
}
function getOwnPropertyValue(node, propertyCollectionName, propertyName, setName, memberPath) {
var propertyCollectionInfo = getPropertyCollectionInfo(node, propertyCollectionName, setName, memberPath);
return propertyCollectionInfo ? propertyCollectionInfo[propertyName] : undefined;
}
function getPropertyValue(node, propertyCollectionName, propertyName, setName, memberPath) {
var value,
relativeMemberPath = null;
do {
if (relativeMemberPath !== null) {
value = getOwnPropertyValue(node, propertyCollectionName, propertyName, setName,
self.getPath(node) + relativeMemberPath);
if (value === undefined) {
value = getOwnPropertyValue(node, propertyCollectionName, propertyName, setName, memberPath);
} else {
memberPath = self.getPath(node) + relativeMemberPath;
}
} else {
value = getOwnPropertyValue(node, propertyCollectionName, propertyName, setName, memberPath);
}
if (value !== undefined) {
return value;
}
relativeMemberPath = typeof memberPath === 'string' ?
getRelativeMemberPath(self.getPath(node), memberPath) : null;
node = self.getBase(node);
} while (node);
return undefined;
}
function createSetOnDemand(node, setName) {
//the function checks if there is no set defined on the node's level and create it
var setsNode = innerCore.getChild(node, CONSTANTS.ALL_SETS_PROPERTY);
if (innerCore.getOwnPointerPath(setsNode, setName) === undefined) {
self.createSet(node, setName);
}
}
function loadNodesOfPaths(root, paths) {
var nodes = [],
i,
rootHash = self.getHash(root);
return TASYNC.call(function () {
for (i = 0; i < paths.length; i += 1) {
nodes[i] = self.loadByPath(root, paths[i]);
}
return TASYNC.call(function (n) {
var newn = [];
for (var i = 0; i < n.length; i++) {
if (n[i] !== null) {
newn.push(n[i]);
}
}
return newn;
}, TASYNC.lift(nodes));
}, self.loadPaths(rootHash, paths));
}
//</editor-fold>
//<editor-fold=Modified Methods>
this.getCollectionNames = function (node) {
var result = innerCore.getCollectionNames(node),
i;
for (i = 0; i < result.length; i++) {
// The member collection is coming from being a member of a set and is not a defined relationship.
if (result[i] === CONSTANTS.MEMBER_RELATION) {
result.splice(i, 1);
break;
}
}
return result;
};
//</editor-fold>
//<editor-fold=Added Methods>
this.getSetNames = function (node) {
return collectSetNames(node);
};
this.getOwnSetNames = function (node) {
return collectOwnSetNames(node);
};
this.createSet = function (node, setName) {
var setNode = getSetNodeByName(node, setName);
innerCore.setPointer(innerCore.getChild(node, CONSTANTS.ALL_SETS_PROPERTY), setName, null);
// Ensure the set-node is not deleted at persist.
innerCore.setRegistry(setNode, '_', '_');
setModified(node);
};
this.deleteSet = function (node, setName) {
var setsNode = innerCore.getChild(node, CONSTANTS.ALL_SETS_PROPERTY),
setNode = innerCore.getChild(setsNode, setName);
innerCore.deletePointer(setsNode, setName);
innerCore.deleteNode(setNode, true);
setModified(node);
};
this.renameSet = function (node, oldName, newName) {
var setsNode = innerCore.getChild(node, CONSTANTS.ALL_SETS_PROPERTY),
setNode = innerCore.getChild(setsNode, oldName),
ownSetNames = self.getOwnSetNames(node);
if (ownSetNames.indexOf(newName) !== -1) {
self.deleteSet(node, newName);
}
innerCore.renamePointer(setsNode, oldName, newName);
innerCore.moveNode(setNode, setsNode, undefined, newName);
setModified(node);
};
this.isMemberOf = function (node) {
//TODO we should find a proper way to do this - or at least some support from lower layers would be fine
var coll = self.getCollectionPaths(node, CONSTANTS.MEMBER_RELATION);
var sets = {};
for (var i = 0; i < coll.length; i++) {
var pathArray = coll[i].split('/');
if (pathArray.indexOf(CONSTANTS.META_NODE) === -1) {
//now we simply skip META sets...
var index = pathArray.indexOf(CONSTANTS.ALL_SETS_PROPERTY);
if (index > 0 && pathArray.length > index + 1) {
//otherwise it is not a real set
var ownerPath = pathArray.slice(0, index).join('/');
if (sets[ownerPath] === undefined) {
sets[ownerPath] = [];
}
sets[ownerPath].push(pathArray[index + 1]);
}
}
}
return sets;
};
this.isFullyOverriddenMember = function (node, setName, memberPath) {
var setNames = collectSetNames(node),
ownRelId,
baseRelId;
if (setNames.indexOf(setName) === -1) {
return false;
}
if (innerCore.getBase(node) === null) {
return false;
}
ownRelId = getMemberRelId(node, setName, memberPath);
baseRelId = getMemberRelId(innerCore.getBase(node), setName, memberPath);
if (ownRelId && baseRelId && ownRelId !== baseRelId) {
return true;
}
return false;
};
this.getMemberPaths = function (node, setName) {
var memberRelids = collectInternalMemberRelids(node, setName),
//pathPrefix = '/' + CONSTANTS.ALL_SETS_PROPERTY + '/' + setName + '/',
i, path,
memberPaths = [];
for (i = 0; i < memberRelids.length; i += 1) {
path = collectMemberPath(node, setName, memberRelids[i]);
if (path !== undefined && memberPaths.indexOf(path) === -1) { //null and '' are valid targets
memberPaths.push(path);
}
}
return memberPaths;
};
this.getOwnMemberPaths = function (node, setName) {
var setInfo = getSetInfoByName(node, setName),
relids = setInfo ? self.getRawKeys(setInfo, self.isValidRelid) : [],
allPaths = self.getMemberPaths(node, setName),
paths = [],
i;
for (i = 0; i < allPaths.length; i += 1) {
if (relids.indexOf(getMemberRelId(node, setName, allPaths[i])) !== -1) {
paths.push(allPaths[i]);
}
}
return paths;
};
this.delMember = function (node, setName, memberPath) {
var setMemberNode;
setMemberNode = getOwnSetMemberNode(node, setName, memberPath);
if (setMemberNode) {
innerCore.deleteNode(setMemberNode, true);
}
};
this.addMember = function (node, setName, member) {
var setNode = getSetNodeByName(node, setName),
setMemberRelId = getMemberRelId(node, setName, self.getPath(member)),
setMemberNode;
if (setMemberRelId === null) {
createSetOnDemand(node, setName);
setMemberNode = innerCore.createChild(setNode, CONSTANTS.MAXIMUM_STARTING_RELID_LENGTH + 1);
} else if (!self.isFullyOverriddenMember(node, setName, self.getPath(member))) {
//it was an inherited member, now we override it
// TODO: We pin down the expected behavior here..
setMemberNode = innerCore.copyNode(innerCore.getChild(setNode, setMemberRelId),
setNode, CONSTANTS.MAXIMUM_STARTING_RELID_LENGTH + 1);
innerCore.deleteNode(innerCore.getChild(setNode, setMemberRelId), true);
}
if (setMemberNode) {
innerCore.setPointer(setMemberNode, CONSTANTS.MEMBER_RELATION, member);
// Ensure the member-node entry is not deleted at persist.
innerCore.setRegistry(setMemberNode, '_', '_');
setModified(node);
} else {
logger.warn('member already in set');
}
};
this.getMemberAttributeNames = function (node, setName, memberPath) {
ASSERT(typeof memberPath === 'string');
return collectPropertyNames(node, CONSTANTS.ATTRIBUTES_PROPERTY, setName, memberPath);
};
this.getMemberOwnAttributeNames = function (node, setName, memberPath) {
ASSERT(typeof memberPath === 'string');
return collectOwnPropertyNames(node, CONSTANTS.ATTRIBUTES_PROPERTY, setName, memberPath);
};
this.getMemberAttribute = function (node, setName, memberPath, attrName) {
ASSERT(typeof memberPath === 'string');
return getPropertyValue(node, CONSTANTS.ATTRIBUTES_PROPERTY, attrName, setName, memberPath);
};
this.getMemberOwnAttribute = function (node, setName, memberPath, attrName) {
ASSERT(typeof memberPath === 'string');
return getOwnPropertyValue(node, CONSTANTS.ATTRIBUTES_PROPERTY, attrName, setName, memberPath);
};
this.setMemberAttribute = function (node, setName, memberPath, attrName, attrValue) {
ASSERT(attrValue !== undefined);
var setMemberNode = getSetMemberNode(node, setName, memberPath);
if (setMemberNode) {
innerCore.setAttribute(setMemberNode, attrName, attrValue);
setModified(node);
}
};
this.delMemberAttribute = function (node, setName, memberPath, attrName) {
var setMemberNode = getOwnSetMemberNode(node, setName, memberPath);
if (setMemberNode) {
innerCore.delAttribute(setMemberNode, attrName);
}
};
this.getMemberRegistryNames = function (node, setName, memberPath) {
ASSERT(typeof memberPath === 'string');
return collectPropertyNames(node, CONSTANTS.REGISTRY_PROPERTY, setName, memberPath);
};
this.getMemberOwnRegistryNames = function (node, setName, memberPath) {
ASSERT(typeof memberPath === 'string');
return collectOwnPropertyNames(node, CONSTANTS.REGISTRY_PROPERTY, setName, memberPath);
};
this.getMemberRegistry = function (node, setName, memberPath, regName) {
ASSERT(typeof memberPath === 'string');
return getPropertyValue(node, CONSTANTS.REGISTRY_PROPERTY, regName, setName, memberPath);
};
this.getMemberOwnRegistry = function (node, setName, memberPath, regName) {
ASSERT(typeof memberPath === 'string');
return getOwnPropertyValue(node, CONSTANTS.REGISTRY_PROPERTY, regName, setName, memberPath);
};
this.setMemberRegistry = function (node, setName, memberPath, regName, regValue) {
ASSERT(regValue !== undefined);
var setMemberNode = getSetMemberNode(node, setName, memberPath);
if (setMemberNode) {
innerCore.setRegistry(setMemberNode, regName, regValue);
setModified(node);
}
};
this.delMemberRegistry = function (node, setName, memberPath, regName) {
var setMemberNode = getOwnSetMemberNode(node, setName, memberPath);
if (setMemberNode) {
innerCore.delRegistry(setMemberNode, regName);
}
};
this.getSetAttributeNames = function (node, setName) {
return collectPropertyNames(node, CONSTANTS.ATTRIBUTES_PROPERTY, setName);
};
this.getOwnSetAttributeNames = function (node, setName) {
return collectOwnPropertyNames(node, CONSTANTS.ATTRIBUTES_PROPERTY, setName);
};
this.getSetAttribute = function (node, setName, attrName) {
return getPropertyValue(node, CONSTANTS.ATTRIBUTES_PROPERTY, attrName, setName);
};
this.getOwnSetAttribute = function (node, setName, attrName) {
return getOwnPropertyValue(node, CONSTANTS.ATTRIBUTES_PROPERTY, attrName, setName);
};
this.setSetAttribute = function (node, setName, attrName, attrValue) {
if (hasSet(node, setName)) {
self.setAttribute(getSetNodeByName(node, setName), attrName, attrValue);
setModified(node);
}
};
this.delSetAttribute = function (node, setName, attrName) {
var setInfo = getSetInfoByName(node, setName);
if (setInfo) {
self.delAttribute(getSetNodeByName(node, setName), attrName);
}
};
this.getSetRegistryNames = function (node, setName) {
return collectPropertyNames(node, CONSTANTS.REGISTRY_PROPERTY, setName);
};
this.getOwnSetRegistryNames = function (node, setName) {
return collectOwnPropertyNames(node, CONSTANTS.REGISTRY_PROPERTY, setName);
};
this.getSetRegistry = function (node, setName, regName) {
return getPropertyValue(node, CONSTANTS.REGISTRY_PROPERTY, regName, setName);
};
this.getOwnSetRegistry = function (node, setName, regName) {
return getOwnPropertyValue(node, CONSTANTS.REGISTRY_PROPERTY, regName, setName);
};
this.setSetRegistry = function (node, setName, regName, regValue) {
if (hasSet(node, setName)) {
self.setRegistry(getSetNodeByName(node, setName), regName, regValue);
setModified(node);
}
};
this.delSetRegistry = function (node, setName, regName) {
var setInfo = getSetInfoByName(node, setName);
if (setInfo) {
self.delRegistry(getSetNodeByName(node, setName), regName);
}
};
this.loadMembers = function (node, setName) {
return loadNodesOfPaths(self.getRoot(node), self.getMemberPaths(node, setName));
};
this.loadOwnMembers = function (node, setName) {
return loadNodesOfPaths(self.getRoot(node), self.getOwnMemberPaths(node, setName));
};
// it only works for own members
// if the target set has the same member, it will be removed first
this.moveMember = function (node, memberPath, oldSetName, newSetName) {
var oldSetNode = getSetNodeByName(node, oldSetName),
oldMemberRelid = getOwnMemberRelId(node, oldSetName, memberPath),
oldMemberNode,
setNames = self.getSetNames(node),
newMemberRelid = getOwnMemberRelId(node, newSetName, memberPath),
newSetNode;
ASSERT(oldMemberRelid !== null, 'Only own member can be moved!');
if (setNames.indexOf(newSetName) === -1) {
self.createSet(node, newSetName);
}
oldMemberNode = self.getChild(oldSetNode, oldMemberRelid);
newSetNode = getSetNodeByName(node, newSetName);
if (newMemberRelid !== null) {
self.delMember(node, newSetName, memberPath);
}
self.moveNode(oldMemberNode, newSetNode);
if (self.getOwnMemberPaths(node, oldSetName).length === 0) {
self.deleteSet(node, oldSetName);
}
};
//</editor-fold>
}
return SetCore;
});