In this blog, I will present a sample implementation for a hybrid mobile app using Oracle JET (version 2.0.x) that will display data fetched from Oracle Sales Cloud via Oracle Mobile Cloud Service (version 16.3.x)

 

Building enterprise grade bespoke mobile apps pose a number of challenges. Implementing data retrieval in mobile application client code is incredibly complex because it needs to be shaped it in the required format within reasonable performance limits with all aspects of security handled appropriately. These requirements are addressed by mobile back-end implemented in Mobile Cloud Service (MCS), resulting into a superior user experience that implies increased user adoption.

 

In this sample, we will retrieve Opportunities for a specific Account from Sales Cloud and display on the mobile application.

 

Key Components

Below tables summarizes the key components involved in this solution:

 

Component
Details
Client Application (JET Hybrid app)A JET Hybrid application that communicates with Oracle MCS
Oracle MCSMCS (Mobile Cloud Service) delivers cloud-based, server-side mobile services to enable quick and easy app development.  It reduces complexity and redundancy when creating code blocks by providing ready-to-integrate features and templates.
Oracle  Sales CloudOracle Sales Cloud delivers a wide range of functionality to improve sales effectiveness, better understand customers, and build a pipeline for success. It exposes multiple public REST APIs that can be used to access data stored in Sales Cloud and construct integrations to other systems

 

Life-Cycle Flow

Below diagram shows the life-cycle flow for data flow from Oracle Sales Cloud to Mobile device via MCS:

 

jet-mcs-salescloud.png

 

Below are the main steps involved:

  1. The mobile app initiates connection with the mobile back-end server (MCS) and authenticate the logged in user.
  2. The mobile app make a REST call to custom API
  3. The custom API internally uses connector API to interact with Oracle Sales Cloud
  4. The response received to custom API’s is sent back to display data in the app

 

Below is the security approach followed:

  • Client Side: Hybrid Mobile Application:
    1. Authenticated the mobile application via SSO: On success , status 200 OK, API returns SSO TOKEN
    2. Used this SSO Token in Authorization header while calling MCS Custom API. This token is used to propagate identity to MCS Connector

 

  • Mobile Back-end: Oracle Mobile Cloud Service
    1. MCS API:
      • Developed custom API which in turn calls REST based connector (Oracle Sales Cloud)
    2. MCS Connector:
      • Developed Connector API pointing to Sales Cloud
      • Set the security policy to “oracle/http_saml20_token_bearer_over_ssl_client_policy” , keeping everything as default

1. In order to follow this security approach mentioned in this blog, please ensure that single sign-on (SSO) is set up for your Oracle Cloud account.

2. Both MCS and Sales Cloud service should be in same identity domain.

Component: Oracle Mobile Cloud Service

Step 1: Create a mobile back-end

  • Login into Oracle MCS and create a new mobile back-end, provide a suitable Name and description
  • Enable OAuth Consumer
  • Check-box to select "Enable Single Sign-On"

If the Mobile Backend is in Draft state and you don't see the Enable SSO checkbox, SSO isn't set up for your account. If you want to set it up, have your team's identity domain administrator go to the Oracle Cloud My Services page and configure SSO.

mcs-backend-settings.png

 

Step 2: Create a custom API

Here are the steps to create a custom API:

  • General: Create a new custom API, provide API display Name and API name. This API name translates to the external URL for the custom API for our mobile apps to connect with it.

mcs-api-general.png

  • Endpoints:  The next step is to define REST end points

mcs-api-endpoints.png

          Add details to the endpoint, in this case it is a GET request:

mcs-api-endpoint.png

 

  • Security: For sake of simplicity, we are keeping the disabling the credentials required to access this API

 

  • Implementation:  Here is the implementation code for this custom API, to know more about what you can do with custom code, I would recommend to visit “Implementing Custom APIs”

Package.json

{
  "name" : "rdhsalesapplapi",
  "version" : "1.0.0",
  "description" : "Sales Cloud API ",
  "main" : "rdhsalesapplapi.js",
  "oracleMobile" : {
    "dependencies" : {
      "apis" : { },
      "connectors" : { "/mobile/connector/RDOSCAPIConnectorOriginSecured": "1.0"}
    }
  }
}

 

rdhsalesapplapi.js

 

/**
 * Mobile Cloud custom code service entry point.
 * @param {external:ExpressApplicationObject}
 * service 
 */
module.exports = function (service) {
    /**
     *  The file samples.txt in the archive that this file was packaged with contains some example code.
     */
    service.get('/mobile/custom/RDHSalesApplAPI/opportunities', function (req, res) {
        var sdk = req.oracleMobile;
        var result = [];
        var statusCodeOk = 200;
        var statusCodeError = 404;
        // handling the Rest call response and processing the data
        var handler = function (error, response, body) {
            var responseMessage = JSON.parse(body);
            if (error) {
                responseMessage = error.message;
            } else {
                if (!responseMessage.items) {
                    res.send(statusCodeError, 'No Opportunities found for the user');
                }
            }
            var opps = [];
            opps = responseMessage.items;
            opps.forEach(function (oppty) {
                var temp = {};
                temp.TargetPartyId = oppty.TargetPartyId;
                temp.OptyId = oppty.OptyId;
                temp.OptyNumber = oppty.OptyNumber;
                temp.SalesStage = oppty.SalesStage;
                temp.Name = oppty.Name;
                temp.Revenue = oppty.Revenue;
                result.push(temp);
            });
            res.send(statusCodeOk, result);
            res.end;
        };
        //call for REST api to get list of opportunities
        var optionsList = {};
        var SalesAccountConnectorBaseURI = '/mobile/connector/RDOSCAPIConnectorOriginSecured';       
        optionsList.uri = SalesAccountConnectorBaseURI + '/salesApi/resources/latest/opportunities/';
        console.log('optionList  = ' + JSON.stringify(optionsList));
        sdk.rest.get(optionsList, handler);
    });
};

 

Step 3: Create a connector API

Before moving ahead, I would recommend you to go through this blog MCS Connector APIs: why should you be using them?  to know why connector APIs are required in spite of having the option to implement external service integration using Custom APIs directly

 

The next step is to create REST connector for accessing Oracle Sales Cloud:

 

  • General Configuration: Provide a name and description for new REST Connector API, and the path to the remote service it will expose.

  mcs-connector-general.png

  • Create Rules: User can create rules that automatically add default parameters when calling specific resources on this service. For this sample, we donot require any such rule so skip this option
  • Security Configuration: Use SAML as the client-side security policy in the MCS Connector, i.e. oracle/http_saml20_token_bearer_over_ssl_client_policy

mcs-connector-securityconfiguration.png

 

Step 4: Select API and associate with your Mobile Backend

 

The next step is to select the custom API created and associate it with your mobile  backend.

mcs-backend-api.png

 

Step 4: Test the Custom API

The last step is to test the custom API

 

A. Get Single Sign-On Auth Token

Open the following URL in an incognito or private browser window. The URL formation is as below:

 

<SSO_Token_Endpoint>?clientID=<client_ID>

 

example: https://xyz.oraclecorp.com:443/mobile/platform/sso/token?clientID=5xxxx7-bf49-45c1-aeda-2xxx4

 

The browser login screen shall look like:

browser-sso-login-screen.png

 

Upon Success, the browser will show Single Sign-On OAuth Token:

 

browser-sso-token-screen.png

 

B.  Test Custom API using MCS UI Test Endpoint

  • Select Mobile Backend
  • Paste SSO Token
  • Click Test Endpoint

mcs-api-testendpoint.png

 

 

Upon Success : Status 200 , data would be displayed:

mcs-api-testendpoint-result.png

 

Component: Oracle JET Hybrid Mobile App

Once the mobile back-end is up and ready, our next step is to display the data fetched data from MCS on the mobile interface.

You may please refer to Troubleshooting while developing your First JET based Hybrid Application blog in case of initial issues faced during development/configuration issues.

Project Setup using Yeoman

Yeoman generator for Oracle JET lets you quickly set up a project for use as a Web application or mobile-hybrid application for Android and iOS.

Use following command to generate hybrid application for Android:

yo oraclejet:hybrid oscmcssample --appId=com.rdh.oscmcs --appName="oscmcssample" --template=navBar --platforms=android  

 

 

Cordova Plugin Required

Please refer to Cordova Applications section in Oracle Mobile Cloud Service to obtain details of the cordova plugin.

 

Following cordova plugin needs to be added in our application:

  • oracle-mobile-cloud-cookies: Plugin for authenticating with MCS via SSO
  • cordova-plugin-inappbrowser: Plugin to provide a web browser view, required for displaying SSO Login Page

 

Adding Oracle MCS Cordova SDK

In order to communicate with Oracle MCS, following steps are required:

  1. Download the Cordova SDK from Oracle MCS. Extract the same on your local machine. It will contain Javascript based Cordova SDK , configuration files and documentation
  2. Add Oracle MCS Cordova SDK to your application, Copy mcs.js, mcs.min.js and oracle_mobile_cloud_config.js into the directory where you keep your JavaScript libraries.

 

For example, in this implementation, I have kept these files in mcs folder added in js/libs folder as shown in below image:

mcs-additions.png

 

2. Fill in your mobile backend details in oracle_mobile_cloud_config.js.

var mcs_config = {
  "logLevel": 3,
  "mobileBackends": {
    "RDXTESTSSO": {
      "default": true,
      "baseUrl": "https://xxx.oraclecorp.com:443",
      "applicationKey": "YOUR_BACKEND_APPLICATION_KEY",
      "synchronization": {
        "periodicRefreshPolicy": "PERIODIC_REFRESH_POLICY_REFRESH_NONE",
        "policies": [
          {
            "path": '/mobile/custom/taskApi/*',
            "fetchPolicy": 'FETCH_FROM_SERVICE_ON_CACHE_MISS_OR_EXPIRY',
            "expiryPolicy": 'EXPIRE_ON_RESTART',
            "evictionPolicy": 'EVICT_ON_EXPIRY_AT_STARTUP',
            "updatePolicy": 'QUEUE_IF_OFFLINE',
            "noCache" : false
          },
          {
            "path": '/mobile/custom/firstApi/tasks',
            "fetchPolicy": 'FETCH_FROM_SERVICE_ON_CACHE_MISS'
          },
          {
            "path": '/mobile/custom/secondApi/tasks',
          }
        ],
        "default" :{
          "fetchPolicy": 'FETCH_FROM_SERVICE_IF_ONLINE',
          "expiryPolicy": 'EXPIRE_ON_RESTART'
        }
      },
        "authorization": {
        "basicAuth": {
          "backendId": "YOUR_BACKEND_ID",
          "anonymousToken": "YOUR_BACKEND_ANONYMOUS_TOKEN"
        },
        "oAuth": {
          "clientId": "YOUR_CLIENT_ID",
          "clientSecret": "YOUR_ClIENT_SECRET",
          "tokenEndpoint": "YOUR_TOKEN_ENDPOINT"
        },
        "facebookAuth":{
          "facebookAppId": "YOUR_FACEBOOK_APP_ID",
          "backendId": "YOUR_BACKEND_ID",
          "anonymousToken": "YOUR_BACKEND_ANONYMOUS_TOKEN"
        },
        "ssoAuth":{
          "clientId": "5xxxxxx7-bf49-45c1-aeda-2xxxxx4",
          "clientSecret": "yxxxxxxx",
          "tokenEndpoint": "https://xxx.oraclecorp.com:443/mobile/platform/sso/token"
        }
      }
    }
  }
};

 

For more details, please See Configuring SDK Properties for Cordova.

 

After adding the physical files, update the paths mapping for mcs and mcs_cloud_config  in main.js file under requirejs.config section:

 paths:
                    //injector:mainReleasePaths
                            {
                                'knockout': 'libs/knockout/knockout-3.4.0.debug',
                                'jquery': 'libs/jquery/jquery-2.1.3',
                                'jqueryui-amd': 'libs/jquery/jqueryui-amd-1.11.4',
                                'promise': 'libs/es6-promise/promise-1.0.0',
                                'hammerjs': 'libs/hammer/hammer-2.0.4',
                                'ojdnd': 'libs/dnd-polyfill/dnd-polyfill-1.0.0',
                                'ojs': 'libs/oj/v2.0.2/debug',
                                'ojL10n': 'libs/oj/v2.0.2/ojL10n',
                                'ojtranslations': 'libs/oj/v2.0.2/resources',
                                'text': 'libs/require/text',
                                'signals': 'libs/js-signals/signals',
                                'mcs': 'libs/mcs/mcs',
                                'mcsconf': 'libs/mcs/oracle_mobile_cloud_config'
                            }
                    //endinjector

Implementation Steps

We will be implementing the entire code in dashboard.html and dashboard.js for easy implementation.

 

Add the additional modules: mcs and mcsconf to get loaded in dashboard.js file:

define(['ojs/ojcore', 'knockout', 'jquery', 'mcs', 'mcsconf', 'ojs/ojknockout', 'ojs/ojfilmstrip', 'ojs/ojpagingcontrol', 'ojs/ojbutton'],

 

Initialize following variables in dasbhoardViewModel function

var backend = 'empty';
                self.model = ko.observable('filmstrip-navdots-example');
                self.dataReady = ko.observable(false);
                self.data = ko.observableArray();
                self.buttonSSOLogin = function () {
                    initializeMCS();
                };

 

 

Updated dashboard.html file: Please find attached the updated dashboard.html file

 

Step 1.  Load Mobile Back end’s Configuration into the application:

function initializeMCS() {
                    mcs.MobileBackendManager.platform = new mcs.CordovaPlatform();
                    mcs.MobileBackendManager.setConfig(mcs_config);
                    backend = mcs.MobileBackendManager.getMobileBackend("RDXTESTSSO");
                    if (backend != null) {
                        backend.setAuthenticationType("ssoAuth");
                        ssoLogin();
                    }
                }

Step 2. Authenticate and Log In Using the SDK:

function ssoLogin() {
                    backend.Authorization.authenticate(
                            function (statusCode, data) {
                                console.log(data);
                                console.log(statusCode);
                                alert("SSO Login success, status:" + statusCode);                               
                                fetchSalesCloudData(data.access_token);
                            },
                            function (statusCode, data) {
                                console.log(statusCode + " with message:  " + data);
                                alert("SSO Login failed, statusCode" + statusCode);
                            });
                }

Step 3. In all REST calls to MCS APIs, include the given token in the Authorization header. In this case, we will be passing this token while calling API to fetch data from our SalesCloud custom API:

function fetchSalesCloudData(ssoToken)
                {
                    var mcsbackendURL = mcs_config.mobileBackends.RDXTESTSSO.baseUrl + "/mobile/custom/RDHSalesApplAPI/opportunities";
                    console.log(mcsbackendURL);
                    var token = "Bearer " + ssoToken;
                    console.log(token);
                    var settings = {
                        "async": true,
                        "crossDomain": true,
                        "url": mcsbackendURL,
                        "method": "GET",
                        "headers": {
                            "authorization": token
                        }
                    };
                    $.ajax(settings).done(function (response) {
                        console.log(response);
                        $.each(response, function () {
                            self.data.push({
                                Name: this.Name,
                                OptyId: this.OptyId,
                                OptyNumber: this.OptyNumber,
                                SalesStage: this.SalesStage,
                                Revenue: this.Revenue
                            });
                        });
                        self.dataReady = true;
                        displaySalesCloudData();
                    });
                }

Step 4: Display data using Oracle JET filmstrip component

function displaySalesCloudData()
                {
                    console.log("inside displayFilmStrip");
                    self.pagingModel = null;
                    getItemInitialDisplay = function (index)
                    {
                        return index < 1 ? '' : 'none';
                    };
                    getPagingModel = function ()
                    {
                        if (!self.pagingModel)
                        {
                            var filmStrip = $("#filmStrip");
                            var pagingModel = filmStrip.ojFilmStrip("getPagingModel");
                            self.pagingModel = pagingModel;
                        }
                        return self.pagingModel;
                    };
                }

 

Build and Run the application on Android emulator/device

 

In your command prompt, please change directory to project folder and run the following command:

 

Build the application using following command

 grunt build --platform=android

 

Once build is success, then run the application using following command, assuming android emulator is already up and running:

grunt serve --platform=android  --disableLiveReload=true  

 

Output

Please find attached the screen-shot output of the emulator:

1. Application Icon:

app-icon.png

 

2. SSO Login

 

app-dashboard-sso-login-button.png

 

3. SSO Login view in embedded web-view. Enter mobile user credentials and press SignIn Button

app-login-page.png

 

4. Success Alert message

app-login-success.png

5. Display of Sales Cloud data on view using JET Filmstrip component

app-dashboard-filmstrip.png