/**
* Copyright© 2016, Oracle and/or its affiliates. All rights reserved.
*/
/**
* The entry-point into the Oracle Mobile Cloud Service SDK. The MobileBackendManager has a singleton from which MobileBackend
* objects can be accessed, which in turn provide access to Analytics, Storage, Auth and other capabilities. The
* singleton can be accessed as {@link mcs.mobileBackendManager}.
* @global
* @constructor
*/
function MobileBackendManager(logger, utils, sync) {
var POLICIES_MAP = {
// mcs key
fetchPolicy: {
persistencePropertyName: 'fetchPolicy',
FETCH_FROM_CACHE_SCHEDULE_REFRESH: 'FETCH_FROM_CACHE_SCHEDULE_REFRESH',
FETCH_FROM_SERVICE_IF_ONLINE: 'FETCH_FROM_SERVICE_IF_ONLINE',
FETCH_FROM_CACHE: 'FETCH_FROM_CACHE',
FETCH_FROM_SERVICE: 'FETCH_FROM_SERVICE',
FETCH_FROM_SERVICE_ON_CACHE_MISS: 'FETCH_FROM_SERVICE_ON_CACHE_MISS',
FETCH_FROM_SERVICE_ON_CACHE_MISS_OR_EXPIRY: 'FETCH_FROM_SERVICE_ON_CACHE_MISS_OR_EXPIRY',
FETCH_WITH_REFRESH: 'FETCH_WITH_REFRESH'
},
evictionPolicy: {
persistencePropertyName: 'evictionPolicy',
EVICT_ON_EXPIRY_AT_STARTUP: 'EVICT_ON_EXPIRY_AT_STARTUP',
MANUAL_EVICTION: 'MANUAL_EVICTION'
},
expirationPolicy: {
persistencePropertyName: 'expirationPolicy',
EXPIRE_ON_RESTART: 'EXPIRE_ON_RESTART',
EXPIRE_AFTER: 'EXPIRE_AFTER',
NEVER_EXPIRE: 'NEVER_EXPIRE'
},
updatePolicy: {
persistencePropertyName: 'updatePolicy',
QUEUE_IF_OFFLINE: 'QUEUE_IF_OFFLINE',
UPDATE_IF_ONLINE: 'UPDATE_IF_ONLINE'
},
refreshPolicy: {
persistencePropertyName: 'refreshPolicy',
PeriodicallyRefreshExpiredResource: ''
},
conflictResolutionPolicy: {
persistencePropertyName: 'conflictResolutionPolicy',
SERVER_WINS: 'SERVER_WINS',
PRESERVE_CONFLICT: 'PRESERVE_CONFLICT',
CLIENT_WINS: 'CLIENT_WINS'
},
noCache: {
persistencePropertyName: 'noCache',
'false': false,
'true': true
}
};
var _config = null;
var _mobileBackends = {};
this.mcsVersion = typeof mcsVersion === 'undefined' ? 'Unknown' : mcsVersion;
if(sync) {
// TODO: restore this functionality
var _originalIsOnline = sync.options.isOnline;
var _isOffline = false;
sync.options.isOnline = function () {
return _isOffline === false ? _originalIsOnline() : !_isOffline;
};
this._setOfflineMode = function (isOffline) {
_isOffline = (typeof isOffline === 'boolean') ? isOffline : true;
};
}
/**
* The platform implementation to use in the application. Callers can derive from [Platform]{@link Platform} to provide a
* specific implementation for device state and capabilities.
* @type {Platform}
* @name MobileBackendManager#platform
*/
this.platform = null;
Object.defineProperty(this, "_config", {
get: function() {
return _config;
}
});
/**
* Sets the configuration for the application. The configuration should be set once before any MobileBackend is accessed.
* @param name {String} The name of the MobileBackend.
* @param config {OracleMobileCloudConfig} The Oracle mobile cloud configuration object.
* @returns {MobileBackend} A MobileBackend object with the specified name.
*/
this.returnMobileBackend = function (name, config) {
if (g.cordova) {
this.platform = new CordovaPlatform(this, logger, utils);
logger.info("The Cordova platform is set!");
}
else {
this.platform = new BrowserPlatform(this, logger, utils);
logger.info("The Browser platform is set!");
}
this.setConfig(config);
logger.info("The config has been set and now it has the backend defined in the config " +
"as the point of entry for the " +
"rest of the functions you need to call.");
return this.getMobileBackend(name);
};
/**
* Create and return mobile backend.
* @param name {String} The name of the MobileBackend.
* @returns {MobileBackend} A MobileBackend object with the specified name.
*/
this.getMobileBackend = function(name) {
if(!this.platform){
logger.error('Platform was not initialized, please initialize mcs.mobileBackendManager.platform');
return null;
}
if(!_config){
logger.error('Mobile Backend Manager was not configured, please set config by mcs.mobileBackendManager.setConfig method');
return null;
}
name = utils.validateConfiguration(name);
if (_mobileBackends[name] != null) {
return _mobileBackends[name];
}
if(_config.mobileBackends[name]){
var backend = new MobileBackend(this, name, _config.mobileBackends[name], this.platform, utils, logger, sync);
_mobileBackends[name] = backend;
return backend;
} else {
logger.error('No mobile backend called " + name + " is defined in MobileBackendManager.config');
return null;
}
};
/**
* Sets the configuration for the application. The configuration should be set once before any MobileBackend is accessed.
* @param config {OracleMobileCloudConfig} The Oracle mobile cloud configuration object.
*/
this.setConfig = function(config) {
if (config.logLevel != null) {
logger.logLevel = config.logLevel;
}
_config = config;
_mobileBackends = {};
if (sync) {
_initPersistenceConfiguration(config);
} else if(config.sync || config.syncExpress){
logger.verbose('WARNING, sync script was not included on page, switch caching off');
}
};
function _initPersistenceConfiguration(config) {
var syncConfig = null;
if(config.sync && config.syncExpress) {
logger.error('WARNING, configuration contains two types synchronisation, please choose one of those types, switch caching off');
sync.options.off = true;
return;
} else if(config.sync){
syncConfig = config.sync;
sync.options.module = new sync.MCSHandler();
} else if(config.syncExpress){
syncConfig = config.syncExpress;
var isOracleRestHandler = config.syncExpress.handler && config.syncExpress.handler === 'OracleRestHandler';
sync.options.module = isOracleRestHandler ? new sync.OracleRestHandler() : new sync.RequestHandler();
} else {
logger.verbose('WARNING, missing synchronization configuration, switch caching off');
sync.options.off = true;
return;
}
sync.options.off = false;
var persistenceConfig = {
default: {
conflictResolutionPolicy: 'CLIENT_WINS',
expirationPolicy: 'NEVER_EXPIRE',
expireAfter: 600,
evictionPolicy: 'MANUAL_EVICTION',
fetchPolicy: 'FETCH_FROM_SERVICE_IF_ONLINE',
updatePolicy: 'QUEUE_IF_OFFLINE',
noCache: false
},
periodicRefreshInterval: syncConfig.backgroundRefreshPolicy || 120,
policies: []
};
var mcsPolicies = syncConfig.policies;
for (var idx in mcsPolicies) {
if (mcsPolicies.hasOwnProperty(idx)) {
var policy = mcsPolicies[idx];
if (policy) {
persistenceConfig.policies.push(_getPersistencePolicy(policy));
} else {
logger.error('WARNING, the ' + policy + 'policy was not found in accepted policies.');
}
}
}
sync.options.Policies = persistenceConfig;
// default sync library settings
sync.options.dbFirst = false;
// fast fix for 404 bug
sync.options.maxSyncAttempts = 1;
sync.options.autoRemoveAfterReachMaxAttemps = true;
// sync.options.syncTimeOut = 3000;
// sync.options.autoSync = true;
// TODO: for next release, add database prefix per user
//sync.options.dbPrefix = 'mcs';
}
function _getPersistencePolicy(mcsPolicy) {
var policy = {};
policy.path = mcsPolicy.path;
for (var prop in mcsPolicy) {
if (mcsPolicy.hasOwnProperty(prop) && prop !== 'path') {
var persMap = POLICIES_MAP[prop];
if (!persMap) {
logger.error('WARNING, the ' + prop + ' policy was not found in accepted policies.');
} else if (persMap[mcsPolicy[prop]] === undefined) {
logger.error('WARNING, the ' + prop + ' policy value ' + mcsPolicy[prop] + ' was not found in accepted policy values.');
} else {
policy[persMap.persistencePropertyName] = persMap[mcsPolicy[prop]];
}
}
}
return policy;
}
}