store = sap.OData.createOfflineStore(properties);
store.open(openStoreSuccessCallback, errorCallback);
sap.OData.applyHttpClient();
//sap.OData.removeHttpClient();
definingRequests : {
contacts : "/ContactSet?$expand=ToContactDetails",
customers : "/CustomerSet",
regions : "/RegionSet",
departments : "/DepartmentSet",
countries : "/CountrySet",
jobfunctions : "/JobFunctionSet"
}
cordova create C:\Kapsel_Projects\OfflineDemo com.mycompany.offline OfflineDemo
cd C:\Kapsel_Projects\OfflineDemo
cordova platform add android
cordova create ~/Documents/Kapsel_Projects/OfflineDemo com.mycompany.offline OfflineDemo
cd ~/Documents/Kapsel_Projects/OfflineDemo
cordova platform add ios
cordova run android
or
cordova run ios
cordova plugin add cordova-plugin-network-information
cordova plugin add kapsel-plugin-odata --searchpath %KAPSEL_HOME%/plugins
cordova plugin add kapsel-plugin-logon --searchpath %KAPSEL_HOME%/plugins
or
cordova plugin add kapsel-plugin-odata --searchpath $KAPSEL_HOME/plugins
cordova plugin add kapsel-plugin-logon --searchpath $KAPSEL_HOME/plugins
com.mycompany.offline
http://services.odata.org/V2/OData/OData.svc
cordova run android
or
cordova run ios
http://services.odata.org
http://services.odata.org/V2/(S(readwrite))/OData/OData.svc/
com.mycompany.offline2
http://services.odata.org
cordova create C:\Kapsel_Projects\OfflineDemo2 com.mycompany.offline2 OfflineDemo2
cd C:\Kapsel_Projects\OfflineDemo2
cordova platform add android
cordova create ~/Documents/Kapsel_Projects/OfflineDemo2 com.mycompany.offline2 OfflineDemo2
cd ~/Documents/Kapsel_Projects/OfflineDemo2
cordova platform add ios
cordova plugin add cordova-plugin-network-information
cordova plugin add kapsel-plugin-odata --searchpath %KAPSEL_HOME%/plugins
cordova plugin add kapsel-plugin-logon --searchpath %KAPSEL_HOME%/plugins
or
cordova plugin add kapsel-plugin-odata --searchpath $KAPSEL_HOME/plugins
cordova plugin add kapsel-plugin-logon --searchpath $KAPSEL_HOME/plugins
<html>
<head>
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
<script src="datajs-1.1.2.min.js"></script>
<script>
var appId = "com.mycompany.offline2"; // Change this to app id on server
var applicationContext = null;
var smpServerProtocol = "http";
var smpServerHost = "10.7.168.124";
var smpServerPort = "8080";
var smpURL = null;
var odataSessionID = window.localStorage.getItem("odataSessionID"); //Unsure of the duration of the session. Unregister and register to get a new session
var authStr = null;
var oDataVersion = "2"; //Note, the Offline OData plugin in SP05 only supports OData version 2.
var store = null; //Offline OData store
var startTime = null;
var online = navigator.onLine;
// Optional initial connection context
var context = {
"serverHost": smpServerHost, //Place your SMP 3.0 server name here
"https": smpServerProtocol == "https",
"serverPort": smpServerPort,
"user": "smpAdmin", //user name for registration and OData Endpoint
"password": "", //password for registration and OData Endpoint
//once set can be changed by calling sap.Logon.changePassword()
"communicatorId": "REST",
"passcode": "" //pin code to protect the app. Once set can be changed by calling sap.Logon.managePasscode()
};
window.onerror = onError;
function onError(msg, url, line) {
var idx = url.lastIndexOf("/");
var file = "unknown";
if (idx > -1) {
file = url.substring(idx + 1);
}
navigator.notification.alert("An error occurred in " + file + " (at line # " + line + "): " + msg);
return false; //suppressErrorAlert;
}
function init() {
if (sap.Logger) {
sap.Logger.setLogLevel(sap.Logger.DEBUG); //enables the display of debug log messages from the Kapsel plugins.
sap.Logger.debug("Log level set to DEBUG");
}
register();
console.log("init completed");
}
function register() {
updateStatus2("register called");
sap.Logon.init(logonSuccessCallback, logonErrorCallback, appId, context);
}
function logonSuccessCallback(result) {
console.log("logonSuccessCallback " + JSON.stringify(result));
updateStatus2("Successfully REGISTERED");
applicationContext = result;
smpURL = smpServerProtocol + "://" + applicationContext.registrationContext.serverHost + ":" + applicationContext.registrationContext.serverPort;
//alternatively the authproxy plugin can provide this if SAPKapselHandleHttpRequests=true (not supported on Android in SP 12 and prior versions)
authStr = "Basic " + btoa(applicationContext.registrationContext.user + ":" + applicationContext.registrationContext.password);
}
function logonErrorCallback(error) { //this method is called if the user cancels the registration.
console.log("An error occurred: " + JSON.stringify(error));
if (device.platform == "Android") { //Not supported on iOS
navigator.app.exitApp();
}
}
function unRegister() {
updateStatus2("unregister called");
sap.Logon.core.deleteRegistration(logonUnregisterSuccessCallback, errorCallback);
clearTable("ProductsTable");
}
function logonUnregisterSuccessCallback(result) {
updateStatus2("Successfully UNREGISTERED");
console.log("logonUnregisterSuccessCallback " + JSON.stringify(result));
applicationContext = null;
odataSessionID = "";
window.localStorage.setItem("odataSessionID", "");
}
function errorCallback(e) {
navigator.notification.alert("An error occurred " + JSON.stringify(e));
console.log("An error occurred " + JSON.stringify(e));
updateStatus1("");
if (startTime) {
var endTime = new Date();
var duration = (endTime - startTime)/1000;
updateStatus2("Failed Operation took " + duration + " seconds");
}
}
function getEndPointURL() {
return applicationContext.applicationEndpointURL;
}
function read(isLocal, inErrorState) {
updateStatus2("read request started");
startTime = new Date();
if (!haveAppId()) {
return;
}
var sURL = getEndPointURL() + "/Products?$orderby=Name desc";
if (isLocal === true) { //displays entities that have been created or updated but have not yet been flushed.
if (store && store.getRequestQueueStatus) { //filter is a new features in SP06 of the SDK. getRequestQueueStatus was added in the same SP.
sURL = sURL + "&$filter=sap.islocal()";
}
else {
navigator.notification.alert("Displaying changed records that have not yet been flushed requires the offline store to be open and is a new feature in SP06 of the SDK");
}
}
if (inErrorState === true) {
if (store) {
sURL = sURL + "&$filter=sap.inerrorstate()";
}
else {
navigator.notification.alert("Displaying records that are in an error state requires the offline store to be open");
}
}
var oHeaders = {};
oHeaders['Authorization'] = authStr;
//oHeaders['X-SMP-APPCID'] = applicationContext.applicationConnectionId; //this header is provided by the logon plugin
var request = {
headers : oHeaders,
requestUri : sURL,
method : "GET"
};
console.log("read using " + sURL);
OData.read(request, readSuccessCallback, errorCallback);
}
function readSuccessCallback(data, response) {
var endTime = new Date();
var duration = (endTime - startTime)/1000;
clearTable("ProductsTable");
showScreen("MainDiv");
//this method is also called by read affected entities which could return a single object rather than an array
if (data.results == undefined)
{
var d = {};
d.results = [data]
data = d;
}
updateStatus2("Read " + data.results.length + " records in " + duration + " seconds");
console.log(JSON.stringify(data));
var productsTable = document.getElementById("ProductsTable");
for (var i = 0; i < data.results.length; i++) {
var row = productsTable.insertRow(1);
applyColor(data.results[i], row);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(1);
var cell3 = row.insertCell(2);
var cell4 = row.insertCell(3);
var cell5 = row.insertCell(4);
var cell6 = row.insertCell(5);
cell1.innerHTML = '<input type="radio" name="ID" id="ID" value="' + data.results[i].ID + '">';
if (data.results[i].__metadata.etag) {
cell1.setAttribute("data-etag", data.results[i].__metadata.etag);
}
cell2.innerHTML = data.results[i].Name;
cell3.innerHTML = data.results[i].Description;
cell4.innerHTML = data.results[i].Price;
cell5.innerHTML = data.results[i].Rating;
cell5.hidden = true;
cell6.innerHTML = data.results[i].ReleaseDate;
cell6.hidden = true;
}
}
function applyColor(data, row) {
if (data["@com.sap.vocabularies.Offline.v1.islocal"]) {
row.style.color = "green"
}
if (data["@com.sap.vocabularies.Offline.v1.inErrorState"]) {
row.style.color = "red"
}
if (data["@com.sap.vocabularies.Offline.v1.isDeleteError"]) {
row.style.color = "orange"
}
}
function deleteRecord() {
if (!haveAppId()) {
return;
}
//get the selected record to be deleted.
var form = document.forms["ProductsForm"];
var productsRadioArray = form.ID;
var radioEl = getSelectedRadioElement(productsRadioArray);
if (!radioEl) {
navigator.notification.alert("Please select a product to be deleted");
return;
}
var deleteProductsURL = getEndPointURL() + "/Products(" + radioEl.value + ")";
var oHeaders = {};
oHeaders['Authorization'] = authStr;
//oHeaders['X-SMP-APPCID'] = applicationContext.applicationConnectionId; //this header is provided by the logon plugin
var etag = radioEl.parentElement.getAttribute("data-etag");
if (etag) {
oHeaders['If-Match'] = etag;
}
var request = {
headers : oHeaders,
requestUri : deleteProductsURL,
method : "DELETE"
};
OData.request(request, read, errorCallback);
}
function showUpdateDiv() {
//get the selected record to be deleted.
var productsForm = document.forms["ProductsForm"];
var productsRadioArray = productsForm.ID;
var radioEl = getSelectedRadioElement(productsRadioArray);
if (!radioEl) {
navigator.notification.alert("Please select a product to be updated");
return;
}
var tr = radioEl.parentElement.parentElement;
var id = radioEl.value;
var updateForm = document.forms["UpdateForm"];
updateForm.ID.value = id;
var name = tr.childNodes[1].innerHTML;
updateForm.name.value = name;
var desc = tr.childNodes[2].innerHTML;
updateForm.description.value = desc;
var price = tr.childNodes[3].innerHTML;
updateForm.price.value = price;
var rating = tr.childNodes[4].innerHTML;
updateForm.rating.value = rating;
var releaseDate = tr.childNodes[5].innerHTML;
updateForm.releaseDate.value = releaseDate;
var etag = radioEl.parentElement.getAttribute("data-etag");
updateForm.etag.value = etag;
showScreen("UpdateDiv");
}
function updateRecord() {
var updateForm = document.forms["UpdateForm"];
var updateProductsURL = getEndPointURL() + "/Products(" + updateForm.ID.value + ")";
var oHeaders = {};
var params = {};
params.Name = updateForm.name.value;
params.Description = updateForm.description.value;
params.Price = updateForm.price.value;
params.Rating = updateForm.rating.value; //not used in this example
params.ReleaseDate = updateForm.releaseDate.value; //works with SQL Anywhere
//params.ReleaseDate = "2014-01-01T00:00:00"; //value cannot be null, not used in this example
//params.ReleaseDate = new Date(); //value cannot be null, not used in this example, works with services.odata.org v2
oHeaders['Authorization'] = authStr;
if (updateForm.etag.value) {
oHeaders['If-Match'] = updateForm.etag.value;
}
//oHeaders['X-SMP-APPCID'] = applicationContext.applicationConnectionId; //this header is provided by the logon plugin
var request = {
headers : oHeaders,
requestUri : updateProductsURL,
method : "PUT", //merge not supported for this OData producer
data : params
};
OData.request(request, read, errorCallback);
}
function showCreateDiv() {
if (!haveAppId()) {
return;
}
var createForm = document.forms["CreateForm"];
createForm.ID.value = "";
createForm.name.value = "";
createForm.description.value = "";
createForm.price.value = "";
showScreen("CreateDiv");
}
function createRecord() {
var createForm = document.forms["CreateForm"];
var oHeaders = {};
var params = {};
params.ID = createForm.ID.value;
params.Name = createForm.name.value;
params.Description = createForm.description.value;
params.Price = createForm.price.value;
params.Rating = 1;
params.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() + "/Products",
method : "POST",
data : params
};
OData.request(request, read, errorCallback);
}
//returns the value of the checked radio element in the passed in array of radio elements
function getSelectedRadioElement(radioElementArray) {
if (radioElementArray) {
if (radioElementArray.length) {
for (var i = 0; i < radioElementArray.length; i++) {
if (radioElementArray[i].checked) {
return radioElementArray[i];
}
}
}
else {
if (radioElementArray.checked) {
return radioElementArray; //just one row, radioElementArray is not an array in this case
}
}
}
}
function showScreen(screenIDToShow) {
var screenToShow = document.getElementById(screenIDToShow);
screenToShow.style.display = "block";
var screens = document.getElementsByClassName('screenDiv');
for (var i = 0; i < screens.length; i++) {
if (screens[i].id != screenToShow.id) {
screens[i].style.display = "none";
}
}
}
function clearTable(tableId) {
var productsTable = document.getElementById(tableId);
while(productsTable.rows.length > 1) {
productsTable.deleteRow(1);
}
}
function openStore() {
if (!haveAppId()) {
return;
}
startTime = new Date();
updateStatus2("store.open called");
var properties = {
"name": "ProductsOfflineStore2",
"host": applicationContext.registrationContext.serverHost,
"port": getServerPort(),
"https": applicationContext.registrationContext.https,
"serviceRoot" : appId,
"definingRequests" : {
"ProductsDR2" : "/Products"
}
};
store = sap.OData.createOfflineStore(properties);
store.onrequesterror = onRequestError; //called for each modification error during flush
//var options = {};
store.open(openStoreSuccessCallback, errorCallback/*, options*/);
}
//If the user specifies a port of 0 in the registration screen, it indicates to the Logon plugin to not explicity set a port
function getServerPort() {
var port = 80;
if (applicationContext.registrationContext.serverPort != 0) {
port = applicationContext.registrationContext.serverPort;
}
else if (applicationContext.registrationContext.https) {
port = 443;
}
else {
port = 80;
}
return port;
}
function onRequestError(error) {
navigator.notification.alert("An error occurred while FLUSHING " + JSON.stringify(error));
console.log("An error occurred while FLUSHING " + JSON.stringify(error));
}
function openStoreSuccessCallback() {
var endTime = new Date();
var duration = (endTime - startTime)/1000;
updateStatus2("Store opened in " + duration + " seconds");
updateStatus1("Store is OPEN.");
sap.OData.applyHttpClient(); //Offline OData calls can now be made against datajs.
}
function closeStore() {
if (!store) {
updateStatus2("The store must be opened before it can be closed");
return;
}
updateStatus2("store.close called");
store.close(closeStoreSuccessCallback, errorCallback);
}
function closeStoreSuccessCallback() {
updateStatus1("Store is CLOSED.");
}
//Sends pending modification requests to the server.
function flushStore() {
if (!store) {
updateStatus2("The store must be open before it can be flushed");
return;
}
startTime = new Date();
updateStatus2("store.flush called");
store.flush(flushStoreSuccessCallback, errorCallback);
}
function flushStoreSuccessCallback() {
var endTime = new Date();
var duration = (endTime - startTime)/1000;
updateStatus2("Store flushed in " + duration + " seconds");
}
//After calling this the store will receive any changes from the OData producer.
function refreshStore() {
if (!store) {
updateStatus2("The store must be open before it can be refreshed");
return;
}
startTime = new Date();
updateStatus2("store.refresh called");
store.refresh(refreshStoreCallback, errorCallback);
}
function refreshStoreCallback() {
var endTime = new Date();
var duration = (endTime - startTime)/1000;
updateStatus2("Store refreshed in " + duration + " seconds");
}
//Removes the physical store from the filesystem
function clearStore() {
if (!store) {
updateStatus2("The store must be closed before it can be cleared");
return;
}
store.clear(clearStoreSuccessCallback, errorCallback);
}
function clearStoreSuccessCallback() {
updateStatus1("");
updateStatus2("Store is CLEARED");
store = null;
}
//Uses the Error Archive. You can also view rows that are in an error state using a filter or by looking for an annotation. See the read() method
function showErrors() {
if (!store) {
updateStatus2("The store must be opened before viewing the ErrorArchive");
return;
}
updateStatus2("ErrorArchive request started");
var sURL = getEndPointURL() + "/ErrorArchive";
var oHeaders = {};
oHeaders['Authorization'] = authStr;
//oHeaders['X-SMP-APPCID'] = applicationContext.applicationConnectionId; //this header is provided by the logon plugin
var request = {
headers : oHeaders,
requestUri : sURL,
method : "GET"
};
console.log("read using " + sURL);
OData.read(request, showErrorsSuccessCallback, errorCallback);
}
function showAffectedEntities() {
updateStatus2("show affected entities request started");
startTime = new Date();
var errRadioEl = getErrorRadioElement();
if (errRadioEl != null) {
var affectedURI = errRadioEl.parentElement.getAttribute("data-affected-uri");
console.log("show Affected Entities URL: " + affectedURI);
var oHeaders = {};
oHeaders['Authorization'] = authStr;
var request = {
headers : oHeaders,
requestUri : affectedURI,
method : "GET"
};
OData.request(request, readSuccessCallback, errorCallback);
}
}
function showErrorsSuccessCallback(data, response) {
updateStatus2("ErrorArchive contains " + data.results.length + " records ");
console.log(JSON.stringify(data.results));
clearTable("ErrorsTable");
showScreen("ErrorsDiv");
var productsTable = document.getElementById("ErrorsTable");
for (var i = 0; i < data.results.length; i++) {
var row = productsTable.insertRow(1);
var product = JSON.parse(data.results[i].RequestBody);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(1);
var cell3 = row.insertCell(2);
var cell4 = row.insertCell(3);
var cell5 = row.insertCell(4);
var cell6 = row.insertCell(5);
var cell7 = row.insertCell(6);
var cell8 = row.insertCell(7);
//var cell9 = row.insertCell(8);
cell1.innerHTML = '<input type="radio" name="ID" id="ID" value="' + data.results[i].RequestID + '">';
cell1.setAttribute("data-affected-uri", data.results[i].AffectedEntity.__deferred.uri);
cell2.innerHTML = data.results[i].RequestMethod;
cell3.innerHTML = data.results[i].HTTPStatusCode;
if (product) {
cell4.innerHTML = product.Name;
cell5.innerHTML = product.Description;
cell6.innerHTML = product.Price;
}
cell7.innerHTML = data.results[i].RequestURL;
//var errStr = "<a onclick='showErrors("" + data.results[i].AffectedEntity.__deferred.uri + "")'>" + data.results[i].Message + "</a>";
cell8.innerHTML = data.results[i].Message;
//cell9.innerHTML = "<button onclick='showAffectedEntities("" + data.results[i].AffectedEntity.__deferred.uri + "")'>Show Affected Entities</button>";
}
}
function getErrorRadioElement() {
//get the selected record to be deleted.
var form = document.forms["ErrorsForm"];
var errorsRadioArray = form.ID;
var radioEl = getSelectedRadioElement(errorsRadioArray);
if (!radioEl) {
navigator.notification.alert("Please select an error");
return null;
}
return radioEl;
}
function clearError() {
if (getErrorRadioElement() != null) { //only proceed if the user has selected an error to be erased. Note that as of SP11 erasing one error, erases all the errors.
navigator.notification.confirm(
"Proceeding will revert all operations that are currently in an error state", // message
clearErrors, // callback to invoke with index of button pressed
"Warning", // title
["Continue","Cancel"] // buttonLabels
);
}
}
function clearErrors(buttonIndex) {
if (buttonIndex == 2) {
return
}
var radioEl = getErrorRadioElement();
updateStatus2("Clear ErrorArchive entry started");
var deleteErrorsURL = getEndPointURL() + "/ErrorArchive" + "(" + radioEl.value + ")";
var oHeaders = {};
oHeaders['Authorization'] = authStr;
//oHeaders['X-SMP-APPCID'] = applicationContext.applicationConnectionId; //this header is provided by the logon plugin
var request = {
headers : oHeaders,
requestUri : deleteErrorsURL,
method : "DELETE"
};
OData.request(request, showErrors, errorCallback);
}
function checkRequestQueue() {
if (!store) {
updateStatus2("The store must be opened before checking the request queue");
return;
}
store.getRequestQueueStatus(requestQSuccessCallback, errorCallback)
}
function requestQSuccessCallback(qStatus) {
var statusStr = " contains items to be flushed";
if (qStatus.isEmpty) {
statusStr = " is empty";
}
updateStatus2("Request queue" + statusStr);
}
function haveAppId() {
if (!applicationContext) {
navigator.notification.alert("Please register with the SMP Server before proceeding");
return false;
}
return true;
}
function getDeviceStatusString() {
if (online) {
return "Device is ONLINE";
}
else {
return "Device is OFFLINE";
}
}
function deviceOnline() {
online = true;
updateStatus1("");
}
function deviceOffline() {
online = false;
updateStatus1("");
}
function updateStatus1(msg) {
document.getElementById('statusID').innerHTML = msg + " " + getDeviceStatusString();
console.log(msg + " " + getDeviceStatusString());
}
function updateStatus2(msg) {
var d = new Date();
document.getElementById('statusID2').innerHTML = msg + " at " + addZero(d.getHours()) + ":" + addZero(d.getMinutes()) + "." + addZero(d.getSeconds());
console.log(msg + " at " + addZero(d.getHours()) + ":" + addZero(d.getMinutes()) + "." + addZero(d.getSeconds()));
}
function addZero(input) {
if (input < 10) {
return "0" + input;
}
return input;
}
document.addEventListener("deviceready", init, false);
document.addEventListener("online", deviceOnline, false);
document.addEventListener("offline", deviceOffline, false);
</script>
</head>
<body onload="updateStatus1('');">
<h1>Offline OData Sample 2</h1>
<button id="register" onclick="register()">Register</button>
<button id="unregister" onclick="unRegister()">Unregister</button>
<button id="read" onclick="read()">Read</button>
<button id="read2" onclick="read(true)">Read Local</button>
<button id="read3" onclick="read(false, true)">Filter on Errors</button>
<button id="create" onclick="showCreateDiv()">Create</button>
<button id="update" onclick="showUpdateDiv();">Update</button>
<button id="delete" onclick="deleteRecord()">Delete</button><br>
<button id="openStore" onclick="openStore()">Open Store</button>
<button id="closeStore" onclick="closeStore()">Close Store</button>
<button id="flushStore" onclick="flushStore()">Flush Store</button>
<button id="refreshStore" onclick="refreshStore()">Refresh Store</button>
<button id="clearStore" onclick="clearStore()">Clear Store</button>
<button id="requestQueue" onclick="checkRequestQueue()">Check Request Queue</button><br>
<button id="showErrors" onclick="showErrors()">Check Error Archive</button>
<button id="clearError" onclick="clearError()">Clear Errors</button>
<button id="showAffected" onclick="showAffectedEntities()">Show Affected Entities</button><br>
<span id="statusID"></span><br>
<span id="statusID2"></span>
<div class="screenDiv" id="MainDiv">
<form id="ProductsForm">
<table id="ProductsTable"><tr><th></th><th align="left">Name</th><th align="left">Description</th><th align="left">Price</th></tr></table>
</form>
</div>
<div class="screenDiv" id="CreateDiv" style="display: none">
<h3>Create</h3>
<form id="CreateForm">
ID: <input type="text" name="ID"><br>
Name: <input type="text" name="name"><br>
Desc: <input type="text" name="description" size="45"><br>
Price: <input type="text" name="price"><br>
<button id="update" type=button onclick="createRecord()">Create</button>
</form>
</div>
<div class="screenDiv" id="UpdateDiv" style="display: none">
<h3>Update</h3>
<form id="UpdateForm">
ID: <input type="text" name="ID" readonly><br>
Name: <input type="text" name="name"><br>
Desc: <input type="text" name="description" size="45"><br>
Price: <input type="text" name="price">
<input type="text" name="rating" hidden>
<input type="text" name="releaseDate" hidden>
<input type="text" name="etag" hidden><br><br>
<button id="update" type=button onclick="updateRecord()">Update</button>
</form>
</div>
<div class="screenDiv" id="ErrorsDiv" style="display: none">
<h3>Errors</h3>
<form id="ErrorsForm">
<table id="ErrorsTable"><tr><th></th><th align="left">Op</th><th align="left">Code</th><th align="left">Name</th><th align="left">Desc</th><th align="left">Price</th><th align="left">URL</th><th align="left">Message</th></tr></table>
</form>
</div>
</body>
</html>
cordova run android
or
cordova run ios
http://10.7.171.223:8080/com.mycompany.offline/Products?$orderby=Name%20desc
http://10.7.171.223:8080/com.mycompany.online/Products?$orderby=Name%20desc
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*/);
}
<button id="read2" onclick="read2()">Read2</button><br>
var sURL = applicationContext.applicationEndpointURL + "/Products?$orderby=Name desc";
var sURL = applicationContext.applicationEndpointURL.replace("offline", "online") + "/Products?$orderby=Name desc";
cordova run android
or
cordova run ios
<html>
<head>
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
<script src="datajs-1.1.2.min.js"></script>
<script>
var appId = "com.mycompany.offline"; // Change this to app id on server
var applicationContext = null;
var smpServerProtocol = "http";
var smpServerHost = "10.7.171.223";
var smpServerPort = "8080";
var authStr = "";
var stores = {}; //Offline OData stores
var startTime = null;
var online = navigator.onLine;
var category = "";
var category_id = -1;
// Optional initial connection context
var context = {
"serverHost": smpServerHost, //Place your SMP 3.0 server name here
"https": smpServerProtocol == "https",
"serverPort": smpServerPort,
"user": "myUserName", //user name for registration and the OData Endpoint
"password": "", //password will be provided by the user for registration
//once set can be changed by calling sap.Logon.changePassword()
"communicatorId": "REST",
"passcode": "" //pin code to protect the app. Once set can be changed by calling sap.Logon.managePasscode()
};
window.onerror = onError;
function onError(msg, url, line) {
var idx = url.lastIndexOf("/");
var file = "unknown";
if (idx > -1) {
file = url.substring(idx + 1);
}
navigator.notification.alert("An error occurred in " + file + " (at line # " + line + "): " + msg);
return false; //suppressErrorAlert;
}
function init() {
if (sap.Logger) {
sap.Logger.setLogLevel(sap.Logger.DEBUG); //enables the display of debug log messages from the Kapsel plugins.
sap.Logger.debug("Log level set to DEBUG");
}
register()
console.log("init completed");
}
function register() {
updateStatus2("register called");
sap.Logon.init(logonSuccessCallback, logonErrorCallback, appId, context);
}
function logonSuccessCallback(result) {
console.log("logonSuccessCallback " + JSON.stringify(result));
updateStatus2("Successfully REGISTERED");
applicationContext = result;
//alternatively the authproxy and logon plugincan provide this if SAPKapselHandleHttpRequests=true, (it is by default on iOS)
authStr = "Basic " + btoa(applicationContext.registrationContext.user + ":" + applicationContext.registrationContext.password);
}
function logonErrorCallback(error) { //this method is called if the user cancels the registration.
console.log("An error occurred: " + JSON.stringify(error));
if (device.platform == "Android") { //Not supported on iOS
navigator.app.exitApp();
}
}
function unRegister() {
updateStatus2("unregister called");
sap.Logon.core.deleteRegistration(logonUnregisterSuccessCallback, errorCallback);
clearTable();
}
function logonUnregisterSuccessCallback(result) {
updateStatus2("Successfully UNREGISTERED");
console.log("logonUnregisterSuccessCallback " + JSON.stringify(result));
applicationContext = null;
}
function errorCallback(e) {
navigator.notification.alert("An error occurred " + JSON.stringify(e));
console.log("An error occurred " + JSON.stringify(e));
updateStatus1("");
}
function read() {
updateStatus2("read request started");
startTime = new Date();
clearTable();
if (!haveAppId()) {
return;
}
//var sURL = category + applicationContext.applicationEndpointURL + "/Products?$orderby=Name desc";
sURL = smpServerProtocol + "://" + smpServerHost + ":" + smpServerPort + "/" + category + appId + "/Products?$orderby=Name desc";
var oHeaders = {};
oHeaders['Authorization'] = authStr;
//oHeaders['X-SMP-APPCID'] = applicationContext.applicationConnectionId; //this header is provided by the logon plugin
var request = {
headers : oHeaders,
requestUri : sURL,
method : "GET"
};
console.log("read using " + sURL);
OData.read(request, readSuccessCallback, errorCallback);
}
function readSuccessCallback(data, response) {
var endTime = new Date();
var duration = (endTime - startTime)/1000;
updateStatus2("Read " + data.results.length + " records in " + duration + " seconds");
var productsTable = document.getElementById("ProductsTable");
for (var i = 0; i < data.results.length; i++) {
var row = productsTable.insertRow(1);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(1);
var cell3 = row.insertCell(2);
cell1.innerHTML = data.results[i].Name;
cell2.innerHTML = data.results[i].Description;
cell3.innerHTML = data.results[i].Price;
}
}
function clearTable() {
var productsTable = document.getElementById("ProductsTable");
while(productsTable.rows.length > 1) {
productsTable.deleteRow(1);
}
}
function setCategory(id) {
if (id == 0) {
category_id = 0;
category = "food.";
}
else if (id == 1) {
category_id = 1;
category = "beverages.";
}
else if (id == 2) {
category_id = 2;
category = "electronics.";
}
else {
category_id = -1;
category = "";
}
document.getElementById('statusID3').innerHTML = "Category is " + category.substring(0, category.length - 1);
console.log("Category is " + category.substring(0, category.length - 1));
}
function openStore() {
if (category_id == -1) {
setCategory(0); //set the category to food
}
if (!haveAppId()) {
return;
}
startTime = new Date();
updateStatus2("store.open called for " + category.substring(0, category.length - 1));
var properties = {
"name": category + "OfflineStore",
"host": applicationContext.registrationContext.serverHost,
"port": getServerPort(),
"https": applicationContext.registrationContext.https,
"serviceRoot" : category + appId,
"definingRequests" : {
"ProductsDR" : "/Products?$expand=Category&$filter=Category/ID eq " + category_id
}
};
stores[category_id] = sap.OData.createOfflineStore(properties);
//var options = {};
stores[category_id].open(openStoreSuccessCallback, errorCallback/*, options*/);
}
//If the user specifies a port of 0 in the registration screen, it indicates to the Logon plugin to not explicity set a port
function getServerPort() {
var port = 80;
if (applicationContext.registrationContext.serverPort != 0) {
port = applicationContext.registrationContext.serverPort;
}
else if (applicationContext.registrationContext.https) {
port = 443;
}
else {
port = 80;
}
return port;
}
function openStoreSuccessCallback() {
var endTime = new Date();
var duration = (endTime - startTime)/1000;
updateStatus2("Store opened in " + duration + " seconds");
updateStatus1("Store is OPEN.");
sap.OData.applyHttpClient(); //Offline OData calls can now be made against datajs.
}
function closeStore() {
if (!stores[category_id]) {
updateStatus2("The store must be opened before it can be closed");
return;
}
startTime = new Date();
updateStatus2("store.close called");
stores[category_id].close(closeStoreSuccessCallback, errorCallback);
}
function closeStoreSuccessCallback() {
sap.OData.removeHttpClient();
var endTime = new Date();
var duration = (endTime - startTime)/1000;
updateStatus1("Store is CLOSED.");
updateStatus2("Store closed in " + duration + " seconds");
}
//Removes the physical store from the filesystem
function clearStore() {
if (!stores[category_id]) {
updateStatus2("The store must be closed before it can be cleared");
return;
}
stores[category_id].clear(clearStoreSuccessCallback, errorCallback);
}
function clearStoreSuccessCallback() {
updateStatus1("");
updateStatus2("Store is CLEARED");
stores[category_id] = null;
}
function haveAppId() {
if (!applicationContext) {
navigator.notification.alert("Please register with the SMP Server before proceeding");
return false;
}
return true;
}
function updateStatus1(msg) {
document.getElementById('statusID').innerHTML = msg + " " + getDeviceStatusString();
console.log(msg + " " + getDeviceStatusString());
}
function updateStatus2(msg) {
var d = new Date();
document.getElementById('statusID2').innerHTML = msg + " at " + addZero(d.getHours()) + ":" + addZero(d.getMinutes()) + "." + addZero(d.getSeconds());
console.log(msg + " at " + addZero(d.getHours()) + ":" + addZero(d.getMinutes()) + "." + addZero(d.getSeconds()));
}
function addZero(input) {
if (input < 10) {
return "0" + input;
}
return input;
}
function getDeviceStatusString() {
if (online) {
return "Device is ONLINE";
}
else {
return "Device is OFFLINE";
}
}
function deviceOnline() {
online = true;
updateStatus1("");
}
function deviceOffline() {
online = false;
updateStatus1("");
}
document.addEventListener("deviceready", init, false);
document.addEventListener("online", deviceOnline, false);
document.addEventListener("offline", deviceOffline, false);
</script>
</head>
<body onload="updateStatus1('');">
<h1>Multiple Offline OData Stores Sample</h1>
<button id="register" onclick="register()">Register</button>
<button id="unregister" onclick="unRegister()">Unregister</button>
<button id="read" onclick="read()">Read</button><br>
<button id="openStore" onclick="openStore()">Open Store</button>
<button id="closeStore" onclick="closeStore()">Close Store </button>
<button id="clearStore" onclick="clearStore()">Clear Store</button>
<button id="catFood" onclick="setCategory(0)">Food</button>
<button id="catBeverages" onclick="setCategory(1)">Beverages</button>
<button id="catElectronics" onclick="setCategory(2)">Electronics</button><br>
<span id="statusID"></span><br>
<span id="statusID2"></span><br>
<span id="statusID3"></span>
<table id="ProductsTable"><tr><th align="left">Name</th><th align="left">Description</th><th align="left">Price</th></tr></table>
</body>
</html>
cordova run android
or
cordova run ios
cordova create C:\Kapsel_Projects\OfflineDemo3 com.mycompany.offline3 OfflineDemo3
cd C:\Kapsel_Projects\OfflineDemo3
cordova platform add android
cordova create ~/Documents/Kapsel_Projects/OfflineDemo3 com.mycompany.offline3 OfflineDemo3
cd ~/Documents/Kapsel_Projects/OfflineDemo3
cordova platform add ios
cordova plugin add cordova-plugin-network-information
cordova plugin add kapsel-plugin-odata --searchpath %KAPSEL_HOME%/plugins
cordova plugin add kapsel-plugin-logon --searchpath %KAPSEL_HOME%/plugins
or
cordova plugin add kapsel-plugin-odata --searchpath $KAPSEL_HOME/plugins
cordova plugin add kapsel-plugin-logon --searchpath $KAPSEL_HOME/plugins
cordova run android
or
cordova run ios
"definingRequests" : { //the below requests will be used to populate the offline store
"CategoriesDR" : "/Categories",
"ProductsDR" : "/Products",
"SuppliersDR" : "/Suppliers"
}
/Categories?$orderby=Name desc
/Products?$expand=Supplier,Category&$filter=Category/ID eq 0&$orderby=Name desc
or
/Categories(1)/Products?$expand=Supplier&$orderby=Name desc
"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
}
cordova create C:\Kapsel_Projects\OfflineDemo4 com.mycompany.offline4 OfflineDemo4
cd C:\Kapsel_Projects\OfflineDemo4
cordova platform add android
cordova create ~/Documents/Kapsel_Projects/OfflineDemo4 com.mycompany.offline4 OfflineDemo4
cd ~/Documents/Kapsel_Projects/OfflineDemo4
cordova platform add ios
cordova plugin add cordova-plugin-network-information
cordova plugin add kapsel-plugin-odata --searchpath %KAPSEL_HOME%/plugins
cordova plugin add kapsel-plugin-logon --searchpath %KAPSEL_HOME%/plugins
or
cordova plugin add kapsel-plugin-odata --searchpath $KAPSEL_HOME/plugins
cordova plugin add kapsel-plugin-logon --searchpath $KAPSEL_HOME/plugins
cordova run android
or
cordova run ios
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);
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);
}
"definingRequests" : { //the below requests will be used to populate the offline store
"CategoriesDR" : "/Categories",
"ProductsDR" : "/Products",
"SuppliersDR" : "/Suppliers"
}
store.refresh(refreshStoreCallback, errorCallback, ["SuppliersDR", "ProductsDR"]);
"definingRequests" : { //the below requests will be used to populate the offline store
"CategoriesDR" : "/Categories",
"ProductsDR" : "/Products",
"SuppliersDR" : "/Suppliers"
}
[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
"definingRequests" : {
"ProductsDR2" : "/Products?$expand=Category,Supplier"
}
[endpoint]
Name=com.mycompany.offline2
content_id_header_location=operation
<button id="deepinsert" onclick="batchCreateAndUpdate()">Batch Create and Update</button>
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", //Previously 2.50
"Rating" : 4,
"ReleaseDate" : "2014-01-01T00:00:00"
}
}
]
}
]
};
var params2 = {
__batchRequests: [
{
__changeRequests: [
{
requestUri: getEndPointURL() + "/Categories",
method: "POST",
headers: {
"Content-ID": "1"
},
data: {
"ID": 6,
"Name": "Imported Foods"
}
},
{
requestUri: "$1/Products",
method: "POST",
headers: {
"Content-ID": "2"
},
data : {
"ID" : 199,
"Name" : "Cheese",
"Description" : "Orange, aged 1 year",
"Price" : "4.99",
"Rating" : 1,
"ReleaseDate" : "2014-01-01T00:00:00"
}
},
{
requestUri: "$2/$links/Supplier",
method: "PUT",
data: {
"uri": "Suppliers(1)"
}
}
]
}
]
};
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, batchCallbackSuccess, errorCallback, OData.batchHandler);
}
function batchCallbackSuccess(data, response) {
console.log(JSON.stringify(data));
read();
}
cordova run android
or
cordova run ios
<button id="deepinsert" onclick="deepInsert()">Deep Insert</button>
//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);
}
<th align="left">Category</th>
var cell7 = row.insertCell(6);
...
cell7.innerHTML = data.results[i].Category.Name;
var sURL = getEndPointURL() + "/Products?$expand=Supplier,Category&$orderby=Name desc";
"definingRequests" : {
"ProductsDR2" : "/Products?$expand=Category,Supplier"
}
cordova run android
or
cordova run ios
http://services.odata.org/V2/Northwind/Northwind.svc/$metadata
<Property Name="Picture" Type="Edm.Binary" Nullable="true" MaxLength="Max" FixedLength="false"/>
http://services.odata.org/V2/Northwind/Northwind.svc/Categories(1)/Picture/$value
<img src="http://services.odata.org/V2/Northwind/Northwind.svc/Categories(1)/Picture/$value">
store.registerStreamRequest(...)
https://sapes1.sapdevcenter.com:443/sap/opu/odata/IWFND/RMTSAMPLEFLIGHT/$metadata
<EntityType Name="Carrier" m:HasStream="true" sap:content-version="1">
https://sapes1.sapdevcenter.com:443/sap/opu/odata/IWFND/RMTSAMPLEFLIGHT/CarrierCollection('SR')
<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>
https://sapes1.sapdevcenter.com/sap/opu/odata/IWFND/RMTSAMPLEFLIGHT/CarrierCollection('SR')/$value
http://services.odata.org/V3/OData/OData.svc/$metadata
<Property Name="Photo" Type="Edm.Stream" Nullable="false"/>
http://services.odata.org/V3/OData/OData.svc/PersonDetails(0)?$format=json
{
"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=\""
}
http://services.odata.org/V3/OData/OData.svc/PersonDetails(0)/Photo
http://services.odata.org/V3/OData/OData.svc/PersonDetails(0)/Photo/$value
C:\SAP\MobilePlatform3\Server\log\YKFN00528072A-smp-server.log
http://services.odata.org/V2/OData/OData.svc
to
http://services.odata.org/V3/OData/OData.svc
store.open called at 14:20.20 index.html:270
An error occurred "Unknown network error occured" index.html:69
Device is ONLINE
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
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'.
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);
[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)
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
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);
store.open called at 13:53.33 index.html:270
An error occurred "Unknown network error occured" index.html:69
Device is ONLINE
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
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 |
[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)
[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)
[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)
/Products?$filter=indexof(Name, 'wrench') ge 0
Provided value for the property 'Price' is not compatible with the property
Name=com.mycompany.offline5
request_format=atom
case_sensitive_offline_db=no
http://services.odata.org/V2/OData/OData.svc/Products?$format=json&$filter=tolower(Name) eq 'bread'
vs
http://services.odata.org/V2/OData/OData.svc/Products?$format=json&$filter=Name eq 'bread'
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
40 | |
25 | |
17 | |
14 | |
8 | |
7 | |
7 | |
7 | |
6 | |
6 |