Skip to Content
Author's profile photo Daniel Van Leeuwen

Getting Started with Kapsel – Part 15 — Offline OData (New in SP05)

/wp-content/uploads/2014/09/sap_logo_333927.png

Offline OData

The following instructions are for SP08. If you are using a newer version of the SDK, please see Getting Started with Kapsel in SP13+

The Kapsel Offline OData plugin enables an OData version 2.0 based application that has its data proxied through an SMP server to be used when a device or emulator is offline by creating a store on the device.

store = sap.OData.createOfflineStore(properties);
store.open(openStoreSuccessCallback, errorCallback);

Once the store is open and the custom OData client is applied with the following call, all calls made using the datajs library that match the service root (connection name for the endpoint such as com.mycompany.offline) are routed to the offline store.

sap.OData.applyHttpClient();
//sap.OData.removeHttpClient();

A set of defining requests specify the data that will populate the offline store.

definingRequests : {
  contacts     : "/ContactSet?$expand=ToContactDetails",
  customers    : "/CustomerSet",
  regions      : "/RegionSet",
  departments  : "/DepartmentSet",
  countries    : "/CountrySet",
  jobfunctions : "/JobFunctionSet"
}

The data that will be updated when a device is offline should ideally be data that multiple offline users are not simultaneously updating.  If possible, partition the data to the subset required by each user.  The offline store has a 16 GB limit.  The initial download time, database size and refresh times can be affected by the amount of data being stored on the device.  Adding OData filters to the defining requests to limit the data on the device to the subset of data required is one technique to do this.

An offline store can only be used with one OData service.  For example, one offline store could be associated with one service such as http://services.odata.org/V2/OData/OData.svc/ or http://services.odata.org/V2/Northwind/Northwind.svc/ but not both.

Once the offline store has been created, local changes made to it can be sent out via a call to store.flush().  The offline store can update its copy of the data by calling store.refresh().

The offline store files can be seen at \data\data\com.mycompany.offline2\files when running in an Android emulator as shown below.image9.PNG

OData function imports are not supported as the service metadata document does not describe what changes occur as a result of calling them.  See also Offline OData Version Support for further details on supported features.  For additional details on the Offline OData plugin see the JavaScript file in a project that includes this plugin at

project_name\plugins\com.sap.mp.cordova.plugins.odata\www\OData.js and OfflineStore.js

or the JS Documentation at Kapsel Offline OData Plugin API Reference.

Note, that SP07 of the Kapsel OData SDK is not compatible with versions of the SMP 3.0 server prior to SP06.

When an offline store is opened, the following message may appear in the SMP server’s log due to this incompatibility.

Stack trace: '[-100067] "6" is an invalid system property ID from the client

Note, if an SP06 PL02 SDK is used with the examples in this section, the offline store will open but when making a read request, the following error will appear in the device log such as the Android logcat due to BCP Issue 1580003258.

An error occurred executing SQL statement: SELECT LO_1 ...

The workaround for this is to use SP07 of the SDK or modify the read request to not use an orderby.

The following samples will help demonstrate the Kapsel Offline OData plugin.

OData Based App
This is a simple OData based app that demonstrates how it cannot read data while the device is offline.

OData Based App with the Kapsel Offline OData Plugin
The Offline OData plugin is added to the project to enable the accessing of OData when device is offline.

Offline enabled App with Create, Update, Delete, Access to the Error Archive
Adds CUD operations (create, update, delete) and how to view failed updates in the ErrorArchive.

Offline and Online in One App
Demonstrates an app where a portion of the data is made available when offline.

Using More than one Offline Store
Demonstrates an app where multiple offline stores are opened.

Sample that Switches to Offline Usage once the Network is Unavailable
This sample shows how an application may switch to using an offline store automatically when network connectivity is lost.

Sample that Defines Relationships using $expand
How to use $expand to define relationships between entities when the OData service does not make use of referentialconstraint.

Additional Settings
Demonstrates encryption of the offline store, refreshing a subset of data and use of refresh interval.

Batch Operation
This example shows how to add a new product that references an existing category and supplier in one operation.

Deep Insert
This example shows how to add a category and a new product in one operation.  This feature was added in SP08 of the SDK.

Binary Data/Attachments
This section discusses offlining attachments.

Troubleshooting

Questions and Answers

OData Based App

The following steps will create a simple OData based app that does not use the Kapsel Offline OData plugin.

  • Create the project.
    cordova -d create C:\Kapsel_Projects\OfflineDemo com.mycompany.offline OfflineDemo "{\"plugin_search_path\":\"C:/SAP/MobileSDK3/KapselSDK/plugins/\"}"
    cd C:\Kapsel_Projects\OfflineDemo
    cordova -d platform add android
    
    cordova -d create ~/Documents/Kapsel_Projects/OfflineDemo com.mycompany.offline OfflineDemo "{\"plugin_search_path\":\"/Users/i826567/SAP/MobileSDK3/KapselSDK/plugins/\"}"
    cd ~/Documents/Kapsel_Projects/OfflineDemo
    cordova -d platform add ios
  • Replace C:\Kapsel_Projects\OfflineDemo\www\index.html with the sample code for products.html from the OData appendix.
    Download the latest datajs file (datajs-1.1.2.min.js) from datajs and place it in the www folder.
  • Copy the files to the platform directory by running
    cordova -d prepare
    
  • Use the Android IDE or Xcode to deploy and run the project.
    image1.PNG

    Notice that the application displays products data from the OData producer at http://services.odata.org/V2/OData/OData.svc/Products?$format=json.

    To see additional details of this service, examine the service metadata document at http://services.odata.org/V2/OData/OData.svc/$metadata.

    Now turn on Airplane mode, close the app and reopen it.
    After the default timeout period, an error will appear.
    image2.PNG

    Airplane mode can be turned on in the following manner.
    On Android choose Settings > More > Airplane mode.
    On an iOS device choose Settings > Airplane Mode.
    On an iOS simulator, unplug the Ethernet cable or turn off the WI-FI for the Mac hosting the simulator.

OData Based App with the Kapsel Offline OData Plugin

The following steps will enable the app to be used when the device or simulator is online or offline.

Note, the techniques used in this sample are for learning purposes only.  In a non-demo app, it is recommended that the offline store be used all the time to maintain consistency of the data.

  • Add the Kapsel Offline OData plugin and the Cordova network information plugin.
    cordova -d plugin add com.sap.mp.cordova.plugins.odata
    cordova -d plugin add com.sap.mp.cordova.plugins.logon
    cordova plugin add org.apache.cordova.network-information
    
  • The Offline OData plugin requires that the OData source is proxied through the SMP server.  If needed, review the steps shown in Configuring a Kapsel App in the Management Cockpit.
    Create an Application with the application ID of
    com.mycompany.offline

    Set the endpoint to be the following URL

    http://services.odata.org/V2/OData/OData.svc

    Check Allow anonymous access since this backend does not require a user name or password.
    Note, no SSO mechanism is needed.
    Ensure the rewrite mode is Rewrite URL in SMP.  For offline apps it is important that the URI’s are routed through the SMP server.

    Under the Authentication tab choose the default profile which means that user name and password can be used on the registration screen.

  • Replace www/index.html with the contents of index1.html or index1UI5.html.
  • Modify the variable smpServerHost in index.html to point to your SMP server.
  • Copy the files to the platform directory by running
    cordova -d prepare
    
  • Use the Android IDE or Xcode to deploy and run the project.

    Note that the Offline OData plugin does not support Android Intel Atom (x86) emulators.  It may run on an Intel based device if that device has Intel to ARM translation software.  See also libhoudini.

    Turn off airplane mode and click on Register, Open Offline Store.
    Exit the app.
    Place the device back into airplane mode.
    Reopen the app and click on Open Store, and then Read.
    image3.PNGimage4.PNGimage4UI5.PNG

    Notice that the app now returns the results using the data retrieved from the local store and does so much quicker since a network request is not needed to retrieve the results.

Offline enabled App with Create, Update, Delete and Access to the Error Archive

Note, there is a known issue with this example and the SP06 SMP server due to a problem with redirects.  BCP Issue 1580013675.  The read request will fail.  This problem is not present in the SP05 server and  is addressed in SP06 PL02 and SP07 server versions.

The following steps will extend the app to enable create, update and delete operations and will also display the contents of the ErrorArchive which contains any error that occurred during a flush which attempts to send locally made changes on the device to the OData producer.

Note, there is an incompatibility around escaping backslashes in a JSON payload that causes the flush operation against services.odata.org to fail.  This issue was fixed in SMP 3.0 SDK SP05 PL03 and SP06.

Note, the techniques used in this sample are for learning purposes only.  In a non-demo app, it is recommended that the offline store be used all the time to maintain consistency of the data.

Note, that this example uses a partial service endpoint in the management cockpit.  The endpoint specified is

http://services.odata.org

instead of

http://services.odata.org/V2/(S(readwrite))/OData/OData.svc/

  The full URL causes a redirect to a new URL that contains the URL with a session id in it.

Note, that the temporary OData session ID can be reset in this example by clicking on Clear Offline Store, Unregister, Register, and then Read or Open Store.

  • http://services.odata.org provides an updateable service. Enter the following URL into a browser to generate a temporary link to the updateable service.
        http://services.odata.org/V2/(S(readwrite))/OData/OData.svc/
        Notice that the resultant URL after a redirect has S(session_id) and it is V2 for OData version 2.0.
  • In the management cockpit create a new application with an ID of
    com.mycompany.offline2

    and an endpoint of

    http://services.odata.org

    Check Allow anonymous access since this backend does not require a user name or password.
    Note, no SSO mechanism is needed.
    Ensure the rewrite mode is Rewrite URL in SMP.  For offline apps it is important that the URI’s are routed through the SMP server.
    Under the Authentication tab choose the default profile which means that user name and password can be used on the registration screen.

  • Create the project.
    cordova -d create C:\Kapsel_Projects\OfflineDemo2 com.mycompany.offline2 OfflineDemo2 "{\"plugin_search_path\":\"C:/SAP/MobileSDK3/KapselSDK/plugins/\"}"
    cd C:\Kapsel_Projects\OfflineDemo2
    cordova -d platform add android
    
    cordova -d create ~/Documents/Kapsel_Projects/OfflineDemo2 com.mycompany.offline2 OfflineDemo2 "{\"plugin_search_path\":\"/Users/i826567/SAP/MobileSDK3/KapselSDK/plugins/\"}"
    cd ~/Documents/Kapsel_Projects/OfflineDemo2
    cordova -d platform add ios
  • Add the Kapsel Offline OData plugin and the Cordova network information plugin.
    cordova -d plugin add com.sap.mp.cordova.plugins.odata
    cordova -d plugin add com.sap.mp.cordova.plugins.logon
    cordova plugin add org.apache.cordova.network-information
    
  • Replace C:\Kapsel_Projects\OfflineDemo2\www\index.html with the contents of index2.html.
  • Modify the variable smpServerHost in index.html to point to your SMP server.
  • Copy the files to the platform directory by running
    cordova -d prepare
  • Use the Android IDE or Xcode to deploy and run the project.

    Note that the Offline OData plugin does not support Android Intel Atom (x86) emulators.

    Press the Read button to get a new temporary URL for the OData service.
    Note products can now be added to the list, removed or modified.  This can occur when the device is online or if it is offline, then when the device is online and the Flush button is pressed, the changes are sent to the OData producer.
    image5.PNG

  • Details of any problems sending the changes made when the device was offline to the OData producer can be viewed in the ErrorArchive.  The following steps can be followed to introduce an error.
    With the offline store open, perform a read.  Update the price of bread from 2.50 to 2.99.
    Close the offline store.
    Perform a read and notice the price of bread is 2.50 since the change made with the store closed was not flushed.
    Delete bread from products.
    Open the offline store and perform a read.  Notice that bread appears in products and the price is 2.99.
    Flush the offline store which will cause an error as the previously deleted product bread cannot have it price updated.
    Click on Check Errors to view the contents of the ErrorArchive.  On this screen, the ability to remove the error is provided. 
    image6.PNG

    Additional functionality could be provided to modify the operation and retry it if the problem was an update issue such as one where two different users both modified the same record.
    Note that services.odata.org does not use ETags so the last update wins.  See also Offline OData Conflicts and Errors and ETag.

Offline and Online in One App

The service root for the offline and always online requests must be different.  In this sample requests that are made to

http://10.7.171.223:8080/com.mycompany.offline/Products?$orderby=Name%20desc

are redirected to the Offline Store when it is open and requests to

http://10.7.171.223:8080/com.mycompany.online/Products?$orderby=Name%20desc

are not redirected to the offline store.  The service root is specified when the store is initially opened.

    function openStore() {
        ...
        var properties = {
            "name": "ProductsOfflineStore",
            "host": applicationContext.registrationContext.serverHost,
            "port": applicationContext.registrationContext.serverPort,
            "https": applicationContext.registrationContext.https,
            "serviceRoot" :  appId,
           
            "definingRequests" : {
                "ProductsDR" : "/Products"
            }
        };

        store = sap.OData.createOfflineStore(properties);

        //var options = {};
        store.open(openStoreSuccessCallback, errorCallback/*, options*/);
    }

The following steps demonstrate this using the previous Offline project.
Note, the techniques used in this sample are for learning purposes only.  In a non-demo app, it is recommended that the offline store be used all the time to maintain consistency of the data.

  • Add a second back-end connection to the application com.mycompany.offline with a name of com.mycompany.online in the management cockpit that also points to http://services.odata.org/V2/OData/OData.svc.
    image12.PNG
  • Modify www/index.html and a second read button.
    <button id="read2" onclick="read2()">Read2</button><br>
  • Copy and paste the read method and rename the copied method to be read2
  • Modify the read2 method.  Change this line
    var sURL = applicationContext.applicationEndpointURL + "/Products?$orderby=Name desc";

    to

    var sURL = applicationContext.applicationEndpointURL.replace("offline", "online") + "/Products?$orderby=Name desc";
  • Copy the files to the platform directory by running
    cordova -d prepare
  • Use the Android IDE or Xcode to deploy and run the project.
    Open the Offline store.  Press the Read button and notice the duration the read took.  Now press the Read2 method and notice that it takes longer as the read is not going to the back-end (services.odata.org) rather than being retrieved from the offline store.

Using More than one Offline Store

If the data being used in the app changes perhaps due to having the device being shared by multiple users or perhaps depending on the sales region the sales person is visiting on a particular day, it may make sense to have more than one offline store.  Each store will need to have a unique service root.

The following steps demonstrate this using the previous Offline project.
Note, the techniques used in this sample are for learning purposes only.  In a non-demo app, it is recommended that the offline store be used all the time to maintain consistency of the data.

  • Add three new back-end connections to the application com.mycompany.offline in the management cockpit that also points to http://services.odata.org/V2/OData/OData.svc.
    image13.PNG
  • Replace the www/index.html with index6.html
  • Use the Android IDE or Xcode to deploy and run the project.
    image14.PNG
  • Select the Food button.  Press the Open Store button.  Once the store has opened, press the read button and notice that the results returned are only the entries that belong to the Food category.  Repeat for the other two categories.
  • At this point there are now three stores created and opened, one for each category of product.
    Examine the index.html file.
    Notice that the variable stores is an array that contains the list of opened stores.   
    Notice pressing a category button such as Food or Electronics sets the variables category and category_id equal to a string that represents the name of the category and the id of the category.  These variables are used by the openStore method to set the name, serviceRoot and a filter on the defining request.  They are also used by the read, closeStore and clearStore methods.
    In order to open multiple stores, each store must have a unique name and service root.  The read method must also use the appropriate service root so the request gets directed to the correct store.

Sample that Switches to Offline Usage once the Network is Unavailable

The following sample listens to online and offline notifications and sets a timer to call refresh after a set interval.  When the app starts the offline store is opened, and if the device is online the store is refreshed.  While the device is online, the offline store is not used.  When the device is offline, the OData requests are redirected to the open online store as the sap.OData.applyHttpClient() method is called when the device switches to offline.  When the device regains network connectivity, the method sap.OData.removeHttpClient() is called.

Note, the techniques used in this sample are for learning purposes only.  In a non-demo app, it is recommended that the offline store be used all the time to maintain consistency of the data.

Follow the below steps to try it out.

  • Create the project.
    cordova -d create C:\Kapsel_Projects\OfflineDemo3 com.mycompany.offline3 OfflineDemo3 "{\"plugin_search_path\":\"C:/SAP/MobileSDK3/KapselSDK/plugins/\"}"
    cd C:\Kapsel_Projects\OfflineDemo3
    cordova -d platform add android
    
    cordova -d create ~/Documents/Kapsel_Projects/OfflineDemo3 com.mycompany.offline3 OfflineDemo3 "{\"plugin_search_path\":\"/Users/i826567/SAP/MobileSDK3/KapselSDK/plugins/\"}"
    cd ~/Documents/Kapsel_Projects/OfflineDemo3
    cordova -d platform add ios
  • Replace C:\Kapsel_Projects\OfflineDemo3\www\index.html with the contents of index3.html.
  • Modify the variable smpServerHost in index.html to point to your SMP server.
  • Add the Kapsel and Cordova plugins.
    cordova -d plugin add com.sap.mp.cordova.plugins.odata
    cordova -d plugin add com.sap.mp.cordova.plugins.logon
    cordova plugin add org.apache.cordova.network-information
    
  • Copy the files to the platform directory by running
    cordova prepare
  • Use the Android IDE or Xcode to deploy and run the project.

    image7.PNG

Sample that Defines Relationships using $expand

The definition of a service can be examined by opening the service URL such as http://services.odata.org/V2/OData/OData.svc/.
This shows that there are three collections available named Products, Categories and Suppliers. For further details see the following URL.  http://services.odata.org/V2/OData/OData.svc/$metadata
Notice that Products is defined as an EntityType of OData.Product and it has a set of NavigationProperties.  Specifically it defines that a Product has a Supplier and a Product has a Category.  When the offline store is created it needs to know about these relationships to correctly create the tables and relationships between the tables.  If the metadata does not specify a referentialconstraint as this service does not, the defining requests will need to use the $expand format to specify how the tables are related.  This is explained in more detail at Using Defining Requests to Build Entity Relationships.
The following sample displays a table of categories as links that when clicked on shows the products in the clicked on category and the supplier of the product.  To make this data available when the device is offline, we need all three entities.  The following defining requests were used initially when creating this sample.

"definingRequests" : { //the below requests will be used to populate the offline store
    "CategoriesDR" : "/Categories",
    "ProductsDR" : "/Products",    
    "SuppliersDR" : "/Suppliers"   
}

Then the following query could be used to retrieve the Categories.

/Categories?$orderby=Name desc

When a category is clicked on a second query can be performed to return the products and supplier information for a given category.  Here are a couple of queries that could be used.

/Products?$expand=Supplier,Category&$filter=Category/ID eq 0&$orderby=Name desc
or
/Categories(1)/Products?$expand=Supplier&$orderby=Name desc

Unfortunately, the above queries returns 0 results when the offline store is open since the relationships between the entities are not defined with ReferentialConstraint.  See also ReferentialConstraint Element.
Since we are not able to change the OData service, the relationships can be specified by using expand in the defining requests as shown below.

"definingRequests" : { //the below requests will be used to populate the offline store
    "CategoriesDR" : "/Categories?$expand=Products/Supplier"
    //"ProductsDR" : "/Products?$expand=Category,Supplier"  //this also works
}

Note, the techniques used in this sample are for learning purposes only.  In a non-demo app, it is recommended that the offline store be used all the time to maintain consistency of the data.

Try out the complete example by following the below steps.

  • Create the project.
    cordova -d create C:\Kapsel_Projects\OfflineDemo4 com.mycompany.offline4 OfflineDemo4 "{\"plugin_search_path\":\"C:/SAP/MobileSDK3/KapselSDK/plugins/\"}"
    cd C:\Kapsel_Projects\OfflineDemo4
    cordova -d platform add android
    
    cordova -d create ~/Documents/Kapsel_Projects/OfflineDemo4 com.mycompany.offline4 OfflineDemo4 "{\"plugin_search_path\":\"/Users/i826567/SAP/MobileSDK3/KapselSDK/plugins/\"}"
    cd ~/Documents/Kapsel_Projects/OfflineDemo4
    cordova -d platform add ios
  • Add the Kapsel Offline OData plugin and the Cordova network information plugin.
    cordova -d plugin add com.sap.mp.cordova.plugins.odata
    cordova -d plugin add com.sap.mp.cordova.plugins.logon
    cordova plugin add org.apache.cordova.network-information
    
  • Replace C:\Kapsel_Projects\OfflineDemo4\www\index.html with the contents of index4.html.
  • Modify the variable smpServerHost in index.html to point to your SMP server.
  • Copy the files to the platform directory by running
    cordova -d prepare
  • Use the Android IDE or Xcode to deploy and run the project.
    Press Register > Read > Electronics
    image11.PNG

Additional Settings

The following section provides examples of some additional settings that can be set.
Encrypting the Offline Database
Delta Queries
Refreshing a Subset of the Offline Data
Prepopulate Offline Database and Refresh Interval of Shared Data

Encrypting the Offline Database

To encrypt the data in the offline stores, specify an encryption key.  Without this, it is possible on an Android or iOS simulator to access the UltraLite database files and view the data as shown below.
image10.PNG

The following option can be provided when opening the store to encrypt the stores using AES-256.

var options = {
    "storeEncryptionKey" : "myVerySecretKey123!"
    //"storeEncryptionKey" : applicationContext.registrationContext.password //if using the Logon plugin, the user entered password for the registration can be used if it never changes
};
store.open(openStoreSuccessCallback, errorCallback, options);

A better solution than hardcoding the password would be to generate a random password and then to store it in the datavault provided by the Logon plugin.  Here is an example of how that might look.

var otp = null;  //one time password.  Must be set once the first time the app starts

function logonSuccessCallback() {
    getOneTimePassword();
    ...
}

function getOneTimePassword() {
    sap.Logon.get(getSuccess, errorCallback, "key");
}

function getSuccess(val) {
    if (val == null) {
        val = Math.random().toString(36).substring(16);
        sap.Logon.set(val);
        return;
    }
    otp = val;
}

function openStore() {
    ...
    var options = {
        "storeEncryptionKey" : otp
    };
    store.open(openStoreSuccessCallback, errorCallback, options);
}

Delta Tracking

The Offline OData plugin can work with delta query enabled backends to minimize the communication between the SMP server and the OData producer.  The following links provide additional details.
Delta Queries (Part 1)
Performance Improvement with Caching and Delta Tracking
Delta Query Support

Refreshing a Subset of the Offline Data

When performing a refresh, if it is only a subset of the data that changes often, in the refresh call it is possible to specify which defining requests should be refreshed.  Assume the application has the following defining requests.

"definingRequests" : { //the below requests will be used to populate the offline store
    "CategoriesDR" : "/Categories",
    "ProductsDR" : "/Products",   
    "SuppliersDR" : "/Suppliers"
}

To only refresh the Products and Suppliers, the following call could be made.

store.refresh(refreshStoreCallback, errorCallback, ["SuppliersDR", "ProductsDR"]);

Prepopulate Offline Database and Refresh Interval of Shared Data

The database used on the device to store the offline data is created and optionally initially populated on the SMP server before it is sent to the device the first time the store is opened.  This can speed up the time taken when the offline store opens for the first time.  As well if the data is cached in the SMP server, calls to refresh the data from the device will use the cached data in the SMP server rather than making requests to the OData producer.
Assume the application has the following defining requests.

"definingRequests" : { //the below requests will be used to populate the offline store
    "CategoriesDR" : "/Categories",
    "ProductsDR" : "/Products",   
    "SuppliersDR" : "/Suppliers"
}

Also assume that the following application configuration file is specified in the management cockpit under Applications > com.mycompany.offline > Import Settings

[endpoint]
Name=com.mycompany.offline
prepopulate_offline_db=Y
prepopulate_offline_db_interval=1440

[defining_request]
name=CategoriesDR
is_shared_data=Y
refresh_interval=1440
track_deltas=NEVER
delta_token_lifetime=0

[defining_request]
name=ProductsDR
is_shared_data=Y
refresh_interval=1440
track_deltas=NEVER
delta_token_lifetime=0

[defining_request]
name=SuppliersDR
is_shared_data=Y
refresh_interval=1440
track_deltas=NEVER
delta_token_lifetime=0

The above configuration file specifies that the offline database is prepopulated and filled with data that is at most less than one day old (1440 minutes = 60 minutes * 24 hours).
It also indicates that if the mobile device requests a refresh operation and the data on the server is less than one day old, the SMP server uses the cached data rather than contacting the OData producer.
Note, these options are further explained at Defining an Application Configuration File with Defining Requests.

Batch

If multiple requests need to be made, it is more efficient to send them as one HTTP(S) request than in multiple requests.
The following steps demonstrate how to perform create and an update operation in one request using the create, update, delete app.

See also Batch Operations, Addressing Links between Entries, Referencing Requests in a Change Set (Content-ID Referencing) and $batch Processing.  Note that Content-ID referencing is not supported in SAP NetWeaver Gateway as mentioned under the Constraints section of the last link.

  • Modify the index.html to include the following new button.
    <button id="deepinsert" onclick="batchCreateAndUpdate()">Batch Create and Update</button>
  • Add the following method to the index.html
    function batchCreateAndUpdate() {
            var oHeaders = {
        };
        var params = {
            __batchRequests: [ {
                __changeRequests: [ {
                    requestUri: getEndPointURL() + "/Products",
                    method: "POST",
                    data : {
                        "ID" : 199,
                        "Name" : "Cheese",
                        "Description" : "Orange, aged 1 year",
                        "Price" : "4.99",
                        "Rating" : 1,
                        "ReleaseDate" : "2014-01-01T00:00:00"
                    }
                },
                {
                    requestUri: getEndPointURL() + "/Products(0)",
                    method: "PUT",
                    data: {
                        "ID" : 1,
                        "Name" : "Bread",
                        "Description" : "Whole grain bread",
                        "Price" : "2.99",
                        "ReleaseDate" : "2014-01-01T00:00:00"
                    }
                }
                ]
            }
        ]
        };
        oHeaders['Authorization'] = authStr;
        //oHeaders['X-SMP-APPCID'] = applicationContext.applicationConnectionId;    //this header is provided by the logon plugin
       
        var request = {
            headers : oHeaders,
            requestUri : getEndPointURL() + "/$batch",
            method : "POST",
            data : params
        };
        OData.request(request, read, errorCallback, OData.batchHandler);
    }
    
    
  • Use the Android IDE or Xcode to deploy and run the project.

    Open the offline store and press the Batch Create and Update button.  Notice that a new record Cheese is added and the price of bread is increased from 2.5 to 2.99.
    image17.PNG

Deep Insert

Note, this feature was added in SP08 of the SDK.  A deep insert allows creating a related entity.  With the Kapsel OData Offline plugin the related entity must not be in a one to many relationship.
See also
Create Related Entities When Creating an Entity

This example will add a button that when pressed will add a new category named Toys and a new product named RC Helicopter.  The following steps demonstrate this using the create, update, delete app.

  • Modify the index.html to include the following new button.
    <button id="deepinsert" onclick="deepInsert()">Deep Insert</button>
  • Add the following method to the index.html
    //Example of an insert that also creates a related item (Category). function deepInsert() {    var oHeaders = {};    var params = {        "ID" : 99,        "Name" : "RC Helicopter",        "Description" : "Flight time 5 minutes",        "Price" : "29.99",        "Rating" : 1,        "ReleaseDate" : "2014-01-01T00:00:00",        "Category" : {  //Adding a new category entity            "ID" : 3,            "Name" : "Toys"        },        //adding navigation properties using entity bindings while offline is not currently supported SP08.        //https://msdn.microsoft.com/en-us/library/dd541294(prot.20).aspx        /*"Supplier" : {            "__metadata": {"uri": "/Suppliers(1)"}          }*/    };    oHeaders['Authorization'] = authStr;        var request = {        headers : oHeaders,        requestUri : getEndPointURL() + "/Products",        method : "POST",        data : params    };    OData.request(request, read, errorCallback); } 
  • Modify the ProductsForm table to include an the Category column
    <th align="left">Category</th>
  • Modify the readSuccessCallback to include Category and Supplier details.  Add the new cell for Category.
    var cell7 = row.insertCell(6);
    ...
    cell7.innerHTML = data.results[i].Category.Name;
    
  • Modify the read request to return details of the Supplier and Category so we can confirm that the Deep Insert was successful.
    var sURL = getEndPointURL() + "/Products?$expand=Supplier,Category&$orderby=Name desc";
  • Modify the defining request to include Categories and Suppliers.
    "definingRequests" : {
        "ProductsDR2" : "/Products?$expand=Category,Supplier"
    }
    
  • Use the Android IDE or Xcode to deploy and run the project.

    Open the offline store and press the Deep Insert button.  Notice that a new record for RC Helicopter is added and it belongs to the new category named Toys.
    image15.PNG

Binary Data/Attachments

There are multiple ways to access binary data in OData.  The following demonstrates a few examples.

Edm.binary

http://services.odata.org/V2/Northwind/Northwind.svc/$metadata

contains

<Property Name="Picture" Type="Edm.Binary" Nullable="true" MaxLength="Max" FixedLength="false"/>

The following URL will return the image data.

http://services.odata.org/V2/Northwind/Northwind.svc/Categories(1)/Picture/$value

The following doesn’t appear to show the image.  I am not sure how to make use of the stream returned as the image does not show.

<img src="http://services.odata.org/V2/Northwind/Northwind.svc/Categories(1)/Picture/$value">


Perhaps it is because the Content-Type is application/octet-stream rather than image/jpeg; charset=UTF-8

Media Resources m:HasStream=”true”

Support for this was added in SP08 of the SDK.  It is also possible to enable the end user to decide on an attachment by attachment basis which attachments should be made available while offline by calling

store.registerStreamRequest("stream", 

For additional details see Offline Media Stream Setup.

https://sapes1.sapdevcenter.com:443/sap/opu/odata/IWFND/RMTSAMPLEFLIGHT/$metadata

contains

<EntityType Name="Carrier" m:HasStream="true" sap:content-version="1">
https://sapes1.sapdevcenter.com:443/sap/opu/odata/IWFND/RMTSAMPLEFLIGHT/CarrierCollection('SR')

returns

<link href="CarrierCollection('SR')/$value" rel="edit-media" type="image/gif"/>
<content type="image/gif" src="CarrierCollection('SR')/$value"/>
<m:properties>
    <d:mimeType>image/gif<d:mimeType>
</m:properties>

It is not clear to me how to access the binary data as the following link does not appear to return the binary data.

https://sapes1.sapdevcenter.com/sap/opu/odata/IWFND/RMTSAMPLEFLIGHT/CarrierCollection('SR')/$value

See also
Representing Media Link Entries.

Edm.Stream

This is something introduced in OData v 3.0 and hence is not currently supported in the Kapsel Offline OData plugin with SDK SP08.

http://services.odata.org/V3/OData/OData.svc/$metadata

contains

<Property Name="Photo" Type="Edm.Stream" Nullable="false"/>
http://services.odata.org/V3/OData/OData.svc/PersonDetails(0)?$format=json

returns

{ 
    "odata.metadata":"http://services.odata.org/V3/OData/OData.svc/$metadata#PersonDetails/@Element",
    "PersonID":0,
    "Age":21,
    "Gender":false,
    "Phone":"(505) 555-5939",
    "Address":{ 
        "Street":"2817 Milton Dr.",
        "City":"Albuquerque",
        "State":"NM",
        "ZipCode":"87110",
        "Country":"USA"
    },
    "Photo@odata.mediaETag":"\"nCP1Tf4Uax96eYIWjvoC/6ZflG8=\""
}
   

When accessed via datajs it appears as below.
image16.PNG

It is not clear to me how to access the binary data.  I would have expected a media_src entry to describe the URL to be used to retrieve the binary data.  The following URLs do not appear to return anything.

http://services.odata.org/V3/OData/OData.svc/PersonDetails(0)/Photo
http://services.odata.org/V3/OData/OData.svc/PersonDetails(0)/Photo/$value

Troubleshooting

When the store fails to open or fails during a flush or refresh, additional details regarding the error can often be seen in one of three log files; the SMP server log file, the JavaScript console or the device log.
The Offline component of the SMP server should have its log level increased when debugging.

image8.PNG

The SMP server’s log file is located at

C:\SAP\MobilePlatform3\Server\log\YKFN00528072A-smp-server.log

The JavaScript console log can also be useful to monitor. To do so, Open Chrome and press Ctrl Shift I when using an Android 4.4 emulator or device or use Safari on a Mac and choose Develop iPhone Simulator or device.  See also Debugging Appendix.
Finally the Android or iOS log can also be useful.

The following are some examples of error conditions and the associated logged messages for these problems.

Version 3 OData Endpoint used with store.open

The endpoint in the management cockpit was modified from

http://services.odata.org/V2/OData/OData.svc
to
http://services.odata.org/V3/OData/OData.svc

JavaScript console from debugging an Android device.

store.open called at 14:20.20 index.html:270
An error occurred "Unknown network error occured" index.html:69
 Device is ONLINE

Android LogCat Output

10-29 14:20:20.538: I/chromium(16869): [INFO:CONSOLE(270)] "store.open called at 14:20.20", source: file:///android_asset/www/index.html (270)
10-29 14:20:25.653: E/SMP_ODATA(16869): Failed to open store
10-29 14:20:25.653: E/SMP_ODATA(16869): com.sap.smp.client.odata.exception.ODataNetworkException: Unknown network error occured
10-29 14:20:25.653: E/SMP_ODATA(16869): at com.sap.smp.client.odata.offline.ODataOfflineStore.openStoreSync(ODataOfflineStore.java:500)
10-29 14:20:25.653: E/SMP_ODATA(16869): at com.sap.smp.client.odata.offline.ODataOfflineStore$OpenStoreWithOptionsThread.run(ODataOfflineStore.java:406)
10-29 14:20:25.653: E/SMP_ODATA(16869): Caused by: com.sap.smp.client.odata.offline.ODataOfflineException: [-10210] The operation failed due to an error on the server.
10-29 14:20:25.653: E/SMP_ODATA(16869): ... 2 more

Here are some snippets from the SMP server log file.

2014 10 29 14:20:37#0-400#ERROR#com.sap.mobile.platform.server.mobilink.SessionLogger##anonymous#Thread-213###[-100099] An error occurred while parsing the metadata document for service "https://10.7.171.223:8080/com.mycompany.offline" com.sap.odata.offline.util.MODataException: [-100099] An error occurred while parsing the metadata document for service "https://10.7.171.223:8080/com.mycompany.offline"
...
Caused by: org.apache.olingo.odata2.api.ep.EntityProviderException: Invalid or missing namespace for 'Schema'.

Incorrect properties passed to store.open

Notice that the serviceRoot is incorrect.  It has an x added to the end of value.  The service root should be a connection name such as com.mycompany.offline.

var properties = {
    "name": "ProductsOfflineStore",
    "host": smpServerHost,
    "port": smpServerPort,
    "https": smpServerProtocol == "https",
    "serviceRoot" :  "com.mycompany.offlinex",
    "streamParams" : "custom_header=Authorization:" + authStr + ";",

    "definingRequests" : {
        "ProductsDR" : "/Products"
    }
};
store = sap.OData.createOfflineStore(properties);

JavaScript console from debugging an iOS simulator.

[Log] store.open called at 11:10.06 (index.html, line 270)
[Log] An error occurred "[-10210] The operation failed due to an error on the server." (index.html, line 69)
[Log]  Device is ONLINE (index.html, line 264)

Here are some snippets from the SMP server log file.

2014 10 29 11:09:38#0-400#INFO#com.sap.mobile.platform.server.mobilink.SessionLogger##anonymous#Thread-229####null#null#null#info#Offline#null#null#18730952-12fa-4f42-b611-21b1468c5051#null#1414609778664#null#com.sap.mobile.platform.server.mobilink.SessionLogger:info#Service root: https://10.7.171.223:8080/com.mycompany.offlinex#null#385#null#28#null |
...
2014 10 29 11:09:38#0-400#INFO#com.sap.mobile.platform.server.mobilink.SessionLogger##anonymous#Thread-229####null#null#null#info#Offline#null#null#18730952-12fa-4f42-b611-21b1468c5051#null#1414609778745#null#com.sap.mobile.platform.server.mobilink.SessionLogger:info#Sending HTTP GET "https://10.7.171.223:8080/com.mycompany.offlinex/$metadata"#null#385#null#89#null |
2014 10 29 11:09:38#0-400#ERROR#com.sap.mobile.platform.server.mobilink.SessionLogger##anonymous#Thread-229###[-100025] An error occurred while communicating with the OData server to retrieve the result of request "https://10.7.171.223:8080/com.mycompany.offlinex/$metadata" com.sap.odata.offline.util.MODataException: [-100025] An error occurred while communicating with the OData server to retrieve the result of request "https://10.7.171.223:8080/com.mycompany.offlinex/$metadata"
...
Caused by: com.sap.odata.offline.util.MODataException: [-100010] Retrieve metadata failed because the OData server returned HTTP code, 404, with message: null

Incorrect Credentials Passed to store.open

Notice the addition of 123456 to the authorization header

var properties = {
    "name": "ProductsOfflineStore",
    "host": smpServerHost,
    "port": smpServerPort,
    "https": smpServerProtocol == "https",
    "serviceRoot" :  appID,
    //There is a cookie store for JavaScript which is different from the Java one used by the Offline plugin
    "streamParams" : "custom_header=Authorization:123456" + authStr + ";custom_header=X-SMP-APPCID:" +  appCID + ";",

    "definingRequests" : {
        "ProductsDR" : "/Products"
    }
};
   
store = sap.OData.createOfflineStore(properties);

JavaScript Console from debugging an Android device.

store.open called at 13:53.33 index.html:270
An error occurred "Unknown network error occured" index.html:69
 Device is ONLINE

Android LogCat Output

10-29 13:53:33.651: I/chromium(754): [INFO:CONSOLE(270)] "store.open called at 13:53.33", source: file:///android_asset/www/index.html (270)
10-29 13:53:56.713: E/SMP_ODATA(754): Failed to open store
10-29 13:53:56.713: E/SMP_ODATA(754): com.sap.smp.client.odata.exception.ODataNetworkException: Unknown network error occured
10-29 13:53:56.713: E/SMP_ODATA(754):   at com.sap.smp.client.odata.offline.ODataOfflineStore.openStoreSync(ODataOfflineStore.java:500)
10-29 13:53:56.713: E/SMP_ODATA(754):   at com.sap.smp.client.odata.offline.ODataOfflineStore$OpenStoreWithOptionsThread.run(ODataOfflineStore.java:406)
10-29 13:53:56.713: E/SMP_ODATA(754): Caused by: com.sap.smp.client.odata.offline.ODataOfflineException: [-10207] Communication with the server failed due to invalid authentication
10-29 13:53:56.713: E/SMP_ODATA(754):   ... 2 more

Here are some snippets from the SMP server log file.

2014 10 29 13:53:59#0-400#ERROR#com.sap.mobile.platform.server.coreservices.configuration.service.ApplicationConnectionServiceImpl##anonymous#http-bio-8080-exec-10####null#null#null#error#Registration#null#null#ddafa3cc1fa24acab78726e30bd48967#null#1414619639774#null#com.sap.mobile.platform.server.coreservices.configuration.service.ApplicationConnectionServiceImpl:isAppConnInputValid#Invalid application connection#null#644#null#0#null |
2014 10 29 13:53:59#0-400#ERROR#com.sap.mobile.platform.server.online.filter.application.SMPApplicationSecurityFilter##anonymous#http-bio-8080-exec-10####null#null#null#error#Other#null#null#ddafa3cc1fa24acab78726e30bd48967#null#1414619639774#null#com.sap.mobile.platform.server.online.filter.application.SMPApplicationSecurityFilter:doFilter#Application connection is not found::null#null#644#null#1#null |

SMP Server not reachable during a Flush or Refresh

JavaScript Console output from debugging an iOS simulator.

[Log] store.flush called at 10:58.56 (index.html, line 537)
[Log] An error occurred "[-10060] An error occurred while performing a synchronization.  Reason: -1305 (MOBILINK_COMMUNICATIONS_ERROR) %1:220 %2:The operation couldn't be completed. Connection refused %3:61" (index.html, line 95)
[Log]  Device is ONLINE (index.html, line 531)

Network Disconnected during a Flush or Refresh

JavaScript Console output from debugging an iOS simulator.

[Log] store.open called at 10:12.04 (index.html, line 537)
[Log] Store opened in  0.694 seconds at 10:12.04 (index.html, line 537)
[Log] Store is OPEN. Device is ONLINE (index.html, line 531)
[Log] store.refresh called at 10:12.10 (index.html, line 537)
[Log]  Device is OFFLINE (index.html, line 531)
[Log] An error occurred "[-10060] An error occurred while performing a synchronization.  Reason: -1305 (MOBILINK_COMMUNICATIONS_ERROR) %1:220 %2:The operation couldn't be completed. Network is unreachable %3:51" (index.html, line 95)
[Log]  Device is OFFLINE (index.html, line 531)

Note, that the flush or refresh operation continues with a short network disconnect.
JavaScript Console output

[Log] store.flush called at 10:56.06 (index.html, line 537)
[Log]  Device is OFFLINE (index.html, line 531)
[Log]  Device is ONLINE (index.html, line 531)
[Log] Store flushed in  15.39 seconds at 10:56.22 (index.html, line 537)

Rewrite URL in SMP

When the offline store is open, URLs that match the defining request are handled by the offline store rather than being sent out over the network.  For this to work correctly the option Rewrite URL in SMP much be selected for the rewrite mode in the Back End tab of the management cockpit.  There is a known issue with the SMP SP07 server in that if the endpoint specified does not include a default port such as 443 or 80 but the URL’s returned from a request do or vice versa, the URL’s are not rewritten.  This has been reported as BCP issue 1570293744.

Questions and Answers

Question

Is there any way to add additional “defining Requests” after an OData offline db got created?
There is a product collection with 1 million entries. I do not want to download this complete collection, so I am setting my definingrequest to an OData collection with filter to city eq Berlin. This is working and will create the database for me with a few thousand products. Now I am in another city and want to add the products of that other city, e.g. Hamburg into my already existing offlineDB. Is this somehow possible?

Answer

There is no way to add additional defining requests to an already existing database.  Once a database is created, the defining requests become fixed.
One potential way to work around this is to create multiple stores on your device.  By using different storeName values in the store options, you can have multiple stores existing at the same time.  So you can have a store_Hamburg and a store_Berlin and open either depending on where you are.

Question

Is there any way to perform a free text search on the offline database?
I know that in OData V4 a new $search query parameter got introduced, but I guess this one is not yet available in the offline store.

Answer

The offline store does not yet support the $search query parameter.
However, it does support the $filter indexof operation.  With this, you can do searches such as:

/Products?$filter=indexof(Name, 'wrench') ge 0

to search for entities containing a string

Question

I know that function imports are not supported in offline. But if there are entities with function imports and without function imports, can we use entities without function imports offline?
Also, what about in the case of variables with size more than 512? If any of the collection having variable size more than 512 can it be used when offline?

Answer

We essentially ignore function imports.  So as long as you don’t try to use them, you can offline other entity sets fine.

We currently don’t support KEY properties or REFERENTIAL CONSTRAINT properties with a greater size.  However, all other properties can have a greater size.

Question

I am getting an error when opening my offline store such as

Provided value for the property 'Price' is not compatible with the property

Answer

The V2 spec requires that Edm.Double be represented as a JSON string, but this service is returning them as a JSON floating point number.  The parser in the offline server is strict and expects a string so it is failing when it is parsing the Edm.Double properties.

A work around to this issue is to force the offline server to use ATOM when retrieving the defining requests.  That can be done by configuring the offline application using an INI file and using that under Applications > com.mycompany.offline > Import Settings.

Name=com.mycompany.offline5
request_format=atom

Back to Getting Started With Kapsel

Assigned Tags

      196 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Former Member
      Former Member

      Hi Daniel,

      I managed to fix the issue mentioned in my previous comment. However I am now stuck with a new one.

      I described it in detail right here. Re: OData plugin inclusion on a Cordova Windows project . Would you mind having a look? I think it might be a problem with the Kapsel OData plugin's DLL files not being included correctly in the project.

      Thanks,

      Christopher

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      Sorry, I don't have much experience with Windows Phone 8.1.  I would however recommend upgrading to the latest SP and PL which I believe is SP10 PL04.

      Author's profile photo Former Member
      Former Member

      Daniel Van Leeuwen,

      While opening the offline store for iOS cordova app, I am getting a similar as mentioned bellow whereas my online app is working really awesome. what could be the reason, I don't see really helpful log at SMP server, is there any Port which has to be opened just like how it was in SUP a synchronization port ??

      SMP server is at SP08

      [Log] An error occurred "[-10060] An error occurred while performing a synchronisation.

      Looking forward to hear from you.

      Regards,

      Srinivas Divakarla

      Author's profile photo Former Member
      Former Member

      Hi Daniel,

      I'm able to register on smp server but in offline mode when i click on read button, i'm getting following alert error message. please have a look and suggest me what changes i have to make.error alert.PNG

      also check this:

      var context = {

               "serverHost": "my serverhost",

               "https": smpServerProtocol == "http",

               "serverPort": "8080",

               "user": "myUserName",      

               "password": "myPassword", 

                                        

               "communicatorId": "REST",

               "passcode": "password",

           sap.Logon.managePasscode()

               "unlockPasscode": "password",

               "passcode_CONFIRM":"password",

               "ssoPasscode":"Password1

      }

      please let how to fixed this issue.

      Thanks and Regards

      Md. Manauwar

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      In the SMP Management Cockpit, are you able to highlight com.mycompany.offline application and successfully ping it?

      Does your network use a proxy server?  If the ping fails and you have not configured your SMP server and the application to use the proxy server that might explain the problem.

      Regards,

      Dan van Leeuwen

      Author's profile photo Former Member
      Former Member

      Hi Daniel,

      I'm providing you more details, please have a look.

      1.) In OData Based App with the Kapsel Offline OData Plugin (offline)

      2.) In Offline enabled App with Create, Update, Delete and Access to the Error Archive (offline2)

      3.)In Sample that Switches to Offline Usage once the Network is Unavailable (offline3)


      Above mentioned in all types, able to ping and reached to backend successfully (w.r.t endpoint url, which is mentioned) and also able to register with my smp server but not able to see data once click on read button.


      4.)In Offline and Online in One App

      After adding 2nd backend connection "com.mycompany.online" is also able to ping and reached to backend successfully.

      -----------------------------------------------------------------------------------------------------------

      ----My server is not using any proxy server.

      ---I'm using Google Nexus 9 tab to check my application.


      ------------------------------------------------------------------------------------------------------------

      Is it happening because of sdk version??.see this ( var oDataVersion = "2";  //Note, the Offline OData plugin in SP05 only supports OData version 2.) since i"m using smp3 server sp09 and smp sdk sp10.

      ------------------------------------------------------------------------------------------------------------

      see this also


      (Note that the Offline OData plugin does not support Android Intel Atom (x86) emulators.  It may run on an Intel based device if that device has Intel to ARM translation software.)

      I have attached screen shot, please have a look on my Android studio installed  sdk list.


      android sdk list.PNG

      ------------------------------------------------------------------------------------------------------------------- i have also attached a screen shot of my index.html file. Have  a look

      index.PNG

      suggest me where and what i need to change asap.


      Thanks and Regards

      Md. Manauwar






      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      I would have a look at the troubleshooting section.  After increasing the log level of the SMP server offline OData component, hopefully an error providing some clues will appear in the log file.

      http://scn.sap.com/docs/DOC-65397#troubleshoting

      Regards,

      Dan van Leeuwen

      Author's profile photo Former Member
      Former Member

      Hi Daniel,

      As per your suggestion i have gone through troubleshooting section. i have increased the Log level to debug mode and also I did need-full changes in OfflineStore.js and OData.js Now i'm able to read odata in online mode but still not able to read it in offline mode.

      (Am i passing the correct credential in odata.js as well as in index.html file)

      var properties = {

        "name": "ProductsOfflineStore",

        "host": smpServerHost,

        "port": smpServerPort,

        "serviceRoot" : com.mycompany.offline,

        "streamParams" : "custom_header=Authorization:" + authStr + ";custom_header=X-SMP-APPCID:" +  appCID + ";",

         "definingRequests" : {

          "ProductsDR" : "/Products"

                  }

              };

      var store = sap.OData.createOfflineStore(properties);

      -------------------------------------------------------------------------------------

      I'm using endpoint " http://services.odata.org/V3/OData/OData.svc"  ( previously i was using V2) and able to ping successfuly.

      smp server vesion: smp03 Sp09

      smp sdk version:  smp03 Sp10

      I have attached screen shot of error. Please have a look and suggest solution for this.

      offline odata error.png

      Thanks and Regards

      MD. Manauwar

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      The Offline OData plugin supports the OData V2 spec and not V3 or V4.  Support for V4 is being worked on.  Note, there is a version of this guide that covers SP09 and greater.  This version is for older versions of the SDK.

      Getting Started with Kapsel - Part 1 (SP09+)

      Perhaps recreate the project following the instructions mentioned in the SP09 and SP10 version of the guide?

      Regards,

      Dan van Leeuwen

      Author's profile photo Former Member
      Former Member

      Hi Daniel,

      I have recreated the project mentioned in the sp09 version (earlier also it was based on sp09). But still not able to get offline odata and getting the same error as mentioned earlier. I'm using odata V2.

      Thanks and Regards

      Md. Manauwar

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      What error do you get with the new project?  Is there an error in the SMP server log file that relates to the problem?

      Author's profile photo Former Member
      Former Member

      Hi Daniel,

      I have attached screen shot of device while fetching odata in offline as well as i have mentioned some smp log files details. Please have a look.

      offline odata error.png

      Screenshot_2016-01-06-14-44-25.png

      smp log files:

      -----------------

      1.) Line 54984: 2016 01 05 16:46:28#+0530#ERROR#com.sap.mobile.platform.server.proxy.core.handler.DirectProxy##nosec_identity#http-bio-8080-exec-5##45ad1cc7-2ead-46cc-829f-ebe48f332c6a#com.mycompany.offline#e6d31081-bf17-4002-9185-ee9f6d629564#RequestResponse#400##Response code from backend is 400 for request null |

      2.)Line 56181: 2016 01 05 18:35:05#+0530#ERROR#com.sap.mobile.platform.server.foundation.security.filter.AuthenticationFilter###http-bio-8080-exec-4##45ad1cc7-2ead-46cc-829f-ebe48f332c6a#com.mycompany.offline#317a1373-6231-4571-89bb-b5c2eea4c2bb#RequestResponse###The registered user nosec_identity for application connection doesn't match the login user myUserName |

      (using same user name i m able to register with smp server)

      3.)

      Line 56186: 2016 01 05 18:35:05#+0530#DEBUG#com.sap.mobile.platform.server.online.filter.application.AbstractClientFilter###http-bio-8080-exec-4##45ad1cc7-2ead-46cc-829f-ebe48f332c6a#com.mycompany.offline#317a1373-6231-4571-89bb-b5c2eea4c2bb#RequestResponse#403##<< Set-Cookie: X-SMP-SESSID=34F68F4D7D9CDBAA4025A4EDAD198715D7B14BF22EA78B0F3F4F44952AAC87C2; Path=/; HttpOnly |

      4.)

      Line 56187: 2016 01 05 18:35:14#+0530#DEBUG#com.sap.mobile.platform.server.online.filter.application.AbstractClientFilter##myUserName#http-bio-8080-exec-3##45ad1cc7-2ead-46cc-829f-ebe48f332c6a##37077bf1-61da-4e72-b05f-d51b8704e26b####>> GET /com.mycompany.offline/Products HTTP/1.1 |

      5.)ERROR#com.sap.mobile.platform.server.proxy.core.handler.DirectProxy##nosec_identity#http-bio-8080-exec-3##a31a2051-e1ad-477a-91da-6eba573f924e#com.mycompany.offline#d102c5d7-5b5b-47d5-bace-5e7dac9c767d#RequestResponse#307##Response code from backend is 307 for request null |

      Regards

      Md. Manauwar

      Author's profile photo Michael Appleby
      Michael Appleby

      Please create a new Discussion marked as a Question.  The Comments section of a Blog (or Document) is not the right vehicle for asking questions as the results are not easily searchable.  Once your issue is solved, a Discussion with the solution (and marked with Correct Answer) makes the results visible to others experiencing a similar problem.  If a blog or document is related, put in a link.

      NOTE: Getting the link is easy enough for both the author and Blog.  Simply MouseOver the item, Right Click, and select Copy Shortcut.  Paste it into your Discussion.  You can also click on the url after pasting.  Click on the A to expand the options and select T (on the right) to Auto-Title the url.

      Thanks, Mike (Moderator)

      SAP Technology RIG

      Author's profile photo Rakshit Doshi
      Rakshit Doshi

      Hi Daniel Van Leeuwen,

      We have data in the backend which is marked in Arabic. Earlier we had this issue on SP03 for online based application wherein we used to manually add the encoding of UTF-8 in beans.xml after deployment. Currently for offline it is giving special characters for arabic content.

      Can you please help on how to set utf-8 encoding on the offline store.

      Thanks,

      Rakshit Doshi

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      I don't have first hand experience with this but hopefully the following documentation links provide what you need.

      The offline database used by the offline plugin is an UltraLite SAP SQL Anywhere database. 

      This database can be set to different collation as described here.

      DocCommentXchange

      I believe this can be passed in an offline_db_collation parameter described here.


      Application Configuration File - Developer - SAP Library

      Let me know if that helps. 

      Regards,

      Dan van Leeuwen

      Author's profile photo Rakshit Doshi
      Rakshit Doshi

      Hi Daniel Van Leeuwen

      I am trying to use offline store via a relay server.

      I am setting the properties as below but getting an unknown network error.

      var properties = {

                      "name": "MyStore",

                      "host": "relayserver address",

                      "port": "80",

                      "https": "false",

                      "serviceRoot" :  "aplication id as of management cockpit",

                      "urlSuffix" : "/rs16.5/client/rs.dll/farmid",

                      "definingRequests" : {

                          "AnimalTypes" : "/getAnimalTypesSet"

                      }

                  };

      Am i setting the parameters properly.

      Thanks,

      Rakshit Doshi

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      I have not myself tried it but I am told it should work.  A while back wrote the following content regarding the public relay server.

      http://scn.sap.com/docs/DOC-65469#relay

      That example uses a parameter called resourcePath and farmId on the initial context passed to the Logon plugin.

      If you are not successful let me know the version of the SDK and the platform (Android, iOS/ Windows) you are using and I can try it out as well. 

      Regards,

      Dan van Leeuwen

      Author's profile photo Chirag Chauhan
      Chirag Chauhan

      Hi Daniel,

      Is it possible to change the query parameter defined as part of definingRequests during refresh?

      I have created the offline store with defining request as:

      "definingRequests": {

           "WOSet" : "/WOSet?$expand=WOToOperation&$filter=TimeStamp eq '<current-date>'"

      }

      During refresh, I would like to change the <current-date>.

      Thanks,

      Chirag.

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      Changing the defining request after a store has been opened is not supported.

      Regards,

      Dan van Leeuwen

      Author's profile photo Chirag Chauhan
      Chirag Chauhan

      Hi Dan,

      In SMP Cockpit -> logs, I can see the entry as:

      Delta Link: <URL>?!deltatoken=ML_ODATA_3260_2462_39125

      What's this "ML_ODATA_3260_2462_39125" represents? Is it last sync UTC timestamp?

      Thanks,

      Chirag.

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      I have not myself used delta tokens.  I assume that is a unique id or key used by the delta token mechanism. 

      The following video may also shed some light on offline with delta tokens.

      Unit 1: How Offline OData Works

      https://open.sap.com/courses/mobile2/items/1K3j4R6eR998WrxamoUt6A

      Regards,

      Dan van Leeuwen

      Author's profile photo Chirag Chauhan
      Chirag Chauhan

      Hi Daniel,

      I am getting error as: {"errorCode":"2","errorMessage":"[-10060] An error occurred while performing a synchronization.  Reason: -1305 (MOBILINK_COMMUNICATIONS_ERROR) %1:231 %2: %3:0","errorDomain":"OfflineStoreErrorDomain"} while refreshing subset of data using API store.refresh(storeRefreshSuccessCallback, storeRefreshErrorCallback, ["FunctionsDR", "EquipmentDR"]);

      I am currently working on SMP 3.0 SP08 PL03.

      Thanks,

      Chirag.

      Author's profile photo Thomas Knobloch
      Thomas Knobloch

      Hi Daniel,

      Thanks for all the explanations, it's very helpful. I have a question about delta queries and caching for offline oData. I know that caching can only be used for data that is valid for all users. In my case I can't use that.

      But I only want to synchronize deltas to the client. So I need to use delta queries. In the backend I could implement delta token handling like described above. That means that client fetches data from SMP and only delta is synchronized. Is that right? But what's about authority checks? Example: depending on user (multiple users use same device) I want to synchronize the entities that are relevant for him. Backend oData call would only select relevant objects, but Store in SMP doesn't know what's relevant.

      Does it mean I can't make use of delta query handling via SMP?

      Thanks for helping me, Thomas

      Author's profile photo Former Member
      Former Member

      Hi Experts,

      I m looking for samples how to use the attachments/binary data in an offline scenario.

      I understood the $value is still a constraint for the offline.

      Any suggestions?

      Thanks in advance,

      Regards,

      Moo

      Author's profile photo Michael Appleby
      Michael Appleby

      Unless you are asking for clarification/correction of some part of the Document, please create a new Discussion marked as a Question.  The Comments section of a Blog (or Document) is not the right vehicle for asking questions as the results are not easily searchable.  Once your issue is solved, a Discussion with the solution (and marked with Correct Answer) makes the results visible to others experiencing a similar problem.  If a blog or document is related, put in a link.  Read the Getting Started documents (link at the top right) including the Rules of Engagement. 

      NOTE: Getting the link is easy enough for both the author and Blog.  Simply MouseOver the item, Right Click, and select Copy Shortcut.  Paste it into your Discussion.  You can also click on the url after pasting.  Click on the A to expand the options and select T (on the right) to Auto-Title the url.

      Thanks, Mike (Moderator)

      SAP Technology RIG

      Author's profile photo Miguel Angel Díaz López
      Miguel Angel Díaz López

      Thanks for sharing, We're working with pouch in SMP and we love it, We're saving som offline data in pouch and sending request to CRM backend. The javascript Promises works with pouchdb perfectly, the performance works great too.

      Author's profile photo Former Member
      Former Member

      Hi to all!

      I have seen different error messages when the user has problems with the network (for example), is it possible to custom these error messages following HTTP status code method?

      For example: instead of "An error occurred "[-10060] An error occurred while performing a synchronization. "  implement HTTP 409 and custom message "No connection available"

      In our scenario, we have a outbox offline (yes, app is offline using kapsel plugin) with different items to sync and it is possible to find different errors depending of the item.

      Thank you in advance.

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      I think you would need to do a check in your errorcallback method and if the error is -10060, then report the custom error message to your users.

      Regards,

      Dan van Leeuwen

      Author's profile photo Former Member
      Former Member

      But is it mandatory to handle these error, or can we custom the messages based in HTTP codes?

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      The error messages returned from the Offline OData component are described here.

      DocCommentXchange

      Regards,

      Dan van Leeuwen

      Author's profile photo Former Member
      Former Member

      Thank you for your very useful responses..

      But I have a question, when you have these type of errors, messages are coming from the local database?

      Normally I am finding error like:

      [Log] An error occurred or user cancelled action: {"message":"[-10107] The update entity request failed because the provided entity does not exist."} (app.js, line 1)

      OR

      [Log] An error occurred or user cancelled action: {"message":"[-10104] An error occurred while committing a database transaction.  Reason: 0 (OK)"} (app.js, line 1)

      AND

      [-10047] An error occurred while setting a parameter with an BINARY value in a prepared statement

      These errors are local or it is a problem with the remote server?

      Any clue to fix it?

      Author's profile photo Diego Güizzo
      Diego Güizzo

      Hi,

      App is in "offline creatting application store ..." sap kapsel, never ends.

      What could be the problem?

      2016-08-23 16_48_16-device.bmp - Paint.png

      Regards,

      Diego.

      Author's profile photo Former Member
      Former Member

      You should to debug or create a new post in the forum with additional information about the problem, because with the current explanation is not enough.

      Author's profile photo Edwar Soto
      Edwar Soto

      Hi, People…I need help.

      Daniel, I have this problems with my app in offline Kapsel. :

      1. When I created a new record offline , using a simpleform control to get values from user and then call method “create” of oModel (object sap.ui.model.odata.v2). It work fine, but , I have too a table binding with same entity that I have created. Then the table show 2 records wih same data. Why?.
      2. I have a, another, view with a table control with editable rows and binding to a entity set (path: “/CollectionSet”) offline, then the user modify records and save yours changes, but the table control is updated automaticaly and duplicate rows updated. what is it I’m doing bad?

       

      the same app in online mode work perfect. ?

      like this problem, reported by Pooja Balakrishnan  on March 24, 2015 at 07:28 AM

      https://archive.sap.com/discussions/thread/3716475

       

      Author's profile photo Cosmin Maciuca
      Cosmin Maciuca

      Hi,

      Is it possible to re-upload the file examples (index1...) ?

      The current links are broken.

       

      Thank you,

      Cosmin

      Author's profile photo Virinchy Panangipalli
      Virinchy Panangipalli

      Daniel Van Leeuwen Thanks for the excellent blog series, Since the links used in this blog series are broken, Would it be possible to upload the HTML files used in this project to a GitHub repo?

       

      Thanks

      Virinchy