/** * Copyright© 2016, Oracle and/or its affiliates. All rights reserved. */ /** * Represents a mobile backend in Oracle Mobile Cloud Service and provides access to all capabilities of the backend. * Callers should use MobileBackendManager's [getMobileBackend()]{@link MobileBackendManager#getMobileBackend} method. * @constructor * @global */ function MobileBackend(manager, name, config, platform, utils, logger, persistence) { var _this = this; var AUTHENTICATION_TYPES = utils.AUTHENTICATION_TYPES; var PLATFORM_PATH = 'mobile/platform'; var CUSTOM_CODE_PATH = 'mobile/custom'; var HEADERS = utils.HEADERS; this._config = config; this._baseUrl = utils.validateConfiguration(this._config.baseUrl); var _authenticationType = null; this._getCustomCodeUri = function(path){ var url = "/" + CUSTOM_CODE_PATH; if (strEndsWith(path,"/")) { path = path.slice(0, -1); } return url + '/' + path; }; /** * The name of the MobileBackend as read from the configuration. * @type {String} * @name MobileBackend#name * @readonly */ this.name = name; /** * Get current authorization object. * @returns {Authorization} */ this.authorization = null; /** * Current authorization object. * @type {Authorization} * @name MobileBackend#Authorization * @readonly * @deprecated Will be removed in next version. Use {@link MobileBackend#authorization} instead. */ Object.defineProperty(this, "Authorization", { get: function() { return _this.authorization; } }); /** * Returns the Diagnostics object that enables end-end debugging across application and cloud. * @returns {Diagnostics} */ this.diagnostics = new Diagnostics(platform, utils); /** * Returns the Diagnostics object that enables end-end debugging across application and cloud. * @type {Diagnostics} * @name MobileBackend#Diagnostics * @deprecated Will be deleted in next version. Use {@link MobileBackend#diagnostics} instead. */ Object.defineProperty(this, "Diagnostics", { get: function() { return _this.diagnostics; } }); /** * Returns the CustomCode object that enables calls to custom APIs. * @returns {CustomCode} */ this.customCode = new CustomCode(this, utils, platform); /** * Returns the CustomCode object that enables calls to custom APIs. * @type {CustomCode} * @name MobileBackend#CustomCode * @readonly * @deprecated Will be deleted in next version. Use {@link MobileBackend#customCode} instead. */ Object.defineProperty(this, "CustomCode", { get: function() { return _this.customCode; } }); /** * Returns the Analytics object that enables capture of mobile analytics events. * @returns {Analytics} */ this.analytics = new Analytics(this, platform, utils, logger); /** * Returns the Analytics object that enables capture of mobile analytics events. * @type {Analytics} * @name MobileBackend#Analytics * @readonly * @deprecated Will be deleted in next version. Use {@link MobileBackend#analytics} instead. */ Object.defineProperty(this, "Analytics", { get: function() { return _this.analytics; } }); /** * Returns the Storage object that provides cloud-based object storage capabilities. * @returns {Storage} */ this.storage = new Storage(this, utils, platform, logger); /** * Returns the Storage object that provides cloud-based object storage capabilities. * @type {Storage} * @name MobileBackend#Storage * @readonly * @deprecated Will be deleted in next version. Use {@link MobileBackend#storage} instead. */ Object.defineProperty(this, "Storage", { get: function() { return _this.storage; } }); if(persistence) { /** * Returns the Synchronization object that provides caching and synchronization capabilities. * @readonly * @name MobileBackend#synchronization * @type {Synchronization} * @deprecated Will be deleted in next version. Use {@link MobileBackend#synchronization} instead. */ Object.defineProperty(this, "Synchronization", { get: function () { return _this.synchronization; } }); /** * Returns the Synchronization object that provides caching and synchronization capabilities. * @returns {Synchronization} */ this.synchronization = new Synchronization(manager, this, this._config.synchronization, utils, platform, persistence); } if(Notifications){ /** * Returns the Notifications object that provides notification capabilities. * @returns {Notifications} */ this.notifications = new Notifications(this, utils, platform, logger); /** * Returns the Notifications object that provides notification capabilities. * @type {Notifications} * @name MobileBackend#Notifications * @readonly * @deprecated Will be deleted in next version. Use {@link MobileBackend#notifications} instead. */ Object.defineProperty(this, "Notifications", { get: function() { return _this.notifications; } }); } /** * Returns an instance of the application configuration object. * Callers can download the configuration from the service by invoking loadAppConfig(). * @returns {Object} */ this.appConfig = {}; /** * Returns an instance of the application configuration object. * Callers can download the configuration from the service by invoking loadAppConfig(). * @deprecated Will be deleted in next version. Use {@link MobileBackend#appConfig} instead. * @name MobileBackend#AppConfig * @readonly * @type {Object} */ Object.defineProperty(this, "AppConfig", { get: function() { return _this.appConfig; } }); /** * Constructs a full URL by prepending the prefix for platform API REST endpoints to the given endpoint path. * @param path {String} The relative path of the endpoint following the platform prefix, i.e. {BaseUrl}/mobile/platform. * @returns {String} The full URL. */ this.getPlatformUrl = function (path) { var url = _this._config.baseUrl; // dev instance hack, replace port ends with 1 with 7777 if(_authenticationType == "ssoAuth" && strEndsWith(_this._config.baseUrl,"1")){ url = url.substring(0, url.length - 4) + "7777"; } url = utils.validateConfiguration(url) + "/" + PLATFORM_PATH; if (!strEndsWith(url, "/")) { url += "/"; } return url + path; }; /** * Constructs a full URL by prepending the prefix for custom API REST endpoints to the given endpoint path. * @param path {String} The relative path of the endpoint following the platform prefix, i.e. {BaseUrl}/mobile/custom. * @returns {String} The full URL. */ this.getCustomCodeUrl = function (path) { return utils.validateConfiguration(_this._config.baseUrl) + _this._getCustomCodeUri(path); }; /** * Constructs a full URL, including the prefix, for the OAuth token endpoint. * @returns {String} The full URL for the OAuth token endpoint. */ this.getOAuthTokenUrl = function () { var tokenUri = utils.validateConfiguration(this._config.authorization.oAuth.tokenEndpoint); if(!strEndsWith(tokenUri,"/")) { tokenUri += "/" } return tokenUri; }; /** * Constructs a full URL, including the prefix, for the SSO token endpoint. * @returns {String} The full URL for the SSO token endpoint. */ this.getSSOAuthTokenUrl = function () { var tokenUri = utils.validateConfiguration(_this._config.authorization.ssoAuth.tokenEndpoint); if(!strEndsWith(tokenUri,"/")) { tokenUri += "/" } return tokenUri; }; /** * Populates auth and diagnostics HTTP headers for making REST calls to a mobile backend. * @param [headers] {Object} An optional object with which to populate with the headers. * @returns {Object} The headers parameter that is passed in. If not provided, a new object with the populated * headers as properties of that object is created. */ this.getHttpHeaders = function (module, headers) { if (!headers) { headers = {}; } _this.diagnostics._getHttpHeaders(headers); if(_this.authorization) { if (_this.authorization._getIsAuthorized() && _this.authorization._getIsAnonymous()) { _this.authorization._getAnonymousHttpHeaders(headers); } else { _this.authorization._getHttpHeaders(headers); } } headers[HEADERS.ORACLE_MOBILE_CLIENT_SDK_INFO] = this.getClientSDKInfoHeader(module); return headers; }; this.getClientSDKInfoHeader = function(module){ var infoHeader = manager.platform.isCordova ? utils.PLATFORM_NAMES.CORDOVA : utils.PLATFORM_NAMES.JAVASCRIPT; infoHeader += ' ' + manager.mcsVersion; infoHeader += module && module !== '' ? ' [' + module + ']' : ''; return infoHeader; }; /** * Returns the Authentication type. * @return {String} Authentication type * @deprecated Will be deleted in next version. Use {@link MobileBackend#getAuthenticationType} instead. */ this.getAuthenticationTypeVariable = function(){ return _authenticationType; }; /** * Sets Authentication variable for MobileBackend. * @param type * @deprecated Will be deleted in next version. Use {@link MobileBackend#setAuthenticationType} instead. */ this.setAuthenticationTypeVariable = function(type){ _authenticationType = type; }; /** * Returns the Authentication type. * @return {String} Authentication type */ this.getAuthenticationType = function(){ return _authenticationType; }; /** * Returns the Authorization object that provides authorization capabilities and access to user properties. * @param {string} type. * For Basic Authentication, you would specify "basicAuth" to use the Basic Authentication security schema. * For OAuth authentication, you would specify "oAuth" to use OAuth Authentication security schema. * If you put any type other than those two, it will throw an Exception stating that the type of Authentication that you provided * is not supported at this time. * @type {Authorization} * @example <caption>Example usage of mobileBackend.setAuthenticationType()</caption> * @example var mobileBackend = mcs.mobileBackendManager.getMobileBackend('YOUR_BACKEND_NAME'); * @example mobileBackend.setAuthenicationType("basicAuth"); * //Basic Authorization schema * @example mobileBackend.setAuthenicationType("oAuth"); * //OAuth Authorization schema * @example mobileBackend.setAuthenicationType("facebookAuth"); * //Facebook Authorization schema * @example mobileBackend.setAuthenicationType("ssoAuth"); * //Single Sign On Authorization schema * @example mobileBackend.setAuthenicationType("tokenAuth"); * //Token Exchange Authorization schema */ this.setAuthenticationType = function(type) { var authType = utils.validateConfiguration(type); _this.authorization = null; if (!_this._config.authorization.hasOwnProperty(authType)) { throw logger.Exception("No Authentication Type called " + type + " is defined in MobileBackendManager.config " + "\n" + "check MobileBackendManager.config in authorization object for the following objects:" + "\n" + AUTHENTICATION_TYPES.BASIC + "\n" + AUTHENTICATION_TYPES.OAUTH + "\n"+ AUTHENTICATION_TYPES.FACEBOOK + "\n"+ AUTHENTICATION_TYPES.TOKEN + "\n"+ AUTHENTICATION_TYPES.SSO); } if (_this.authorization && _this.authorization._getIsAuthorized()) { _this.authorization.logout(); } if (authType === AUTHENTICATION_TYPES.BASIC) { _this.authorization = new BasicAuthorization(_this._config.authorization.basicAuth, _this, _this._config.applicationKey, utils, platform, logger); logger.info( "Your Authentication type: " + authType); _authenticationType = authType; } else if (authType === AUTHENTICATION_TYPES.OAUTH) { _this.authorization = new OAuthAuthorization(_this._config.authorization.oAuth, _this, _this._config.applicationKey, utils, platform, logger); logger.info( "Your Authentication type: " + authType); _authenticationType = authType; } else if(authType === AUTHENTICATION_TYPES.FACEBOOK){ _this.authorization = new FacebookAuthorization(_this._config.authorization.facebookAuth,_this, _this._config.applicationKey, utils, platform, logger); logger.info( "Your Authentication type: " + authType); _authenticationType = authType; } else if(authType === AUTHENTICATION_TYPES.SSO){ _this.authorization = new SSOAuthorization(_this._config.authorization.ssoAuth, _this, _this._config.applicationKey, utils, platform, logger); logger.info( "Your Authentication type: " + authType); _authenticationType = authType; } else if(authType === AUTHENTICATION_TYPES.TOKEN){ _this.authorization = new ExternalTokenExchangeAuthorization(_this._config.authorization.tokenAuth, _this, _this._config.applicationKey, utils, platform, logger); logger.info( "Your Authentication type: " + authType); _authenticationType = authType; } return _this.authorization; }; /** * Callback invoked after downloading the application configuration. * @callback MobileBackend~appConfigSuccessCallback * @param statusCode {Number} Any HTTP status code returned from the server, if available. * @param appConfig {Object} The downloaded application configuration object. * @deprecated Use promises instead */ /** * Callback invoked on an error while downloading the application configuration. * @callback MobileBackend~errorCallback * @param statusCode {Number} Any HTTP status code returned from the server, if available. * @param message {String} The HTTP payload from the server, if available, or an error message. * @deprecated Use promises instead */ /** * Downloads the configuration from the service. The AppConfig property will contain the downloaded configuration. * @param [successCallback] {MobileBackend~appConfigSuccessCallback} Optional callback invoked on success (deprecated use promises instead). * @param [errorCallback] {MobileBackend~errorCallback} Optional callback invoked on failure (deprecated use promises instead). * @return {Promise.<NetworkResponse|NetworkResponse>} */ this.loadAppConfig = function(successCallback, errorCallback) { if (!_this.authorization._getIsAuthorized()) { return _this.authorization.authenticateAnonymous() .then(loadAppConfig) .then(loadAppConfigSuccess, loadAppConfigFail); } else { return loadAppConfig() .then(loadAppConfigSuccess, loadAppConfigFail); } function loadAppConfigSuccess(response){ if(successCallback){ successCallback(response.statusCode, response.data); } return response; } function loadAppConfigFail(response){ if(errorCallback != null) { errorCallback(response.statusCode, response.data); } else { return Promise.reject(response); } } function loadAppConfig() { var headers = _this.getHttpHeaders(utils.MODULE_NAMES.APP_CONFIG); headers["Content-Type"] = "application/json"; return platform.invokeService({ method: 'GET', url: _this.getPlatformUrl("appconfig/client"), headers: headers }).catch(invokeServiceFail); function invokeServiceFail(response){ logger.error("App config download failed! with status code: " + response.statusCode); return Promise.reject(response); } } }; // private methods /* * Checks to see if the string ends with a suffix. * @return {boolean} */ function strEndsWith(str, suffix) { return str.match(suffix + '$') == suffix; } }