/** * 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; } }