Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Dan_vL
Product and Topic Expert
Product and Topic Expert
Previous   Home


The SAP Cloud Platform Document Service and SAP Cloud Platform Document Service for Mobile Services provides an on-demand content repository for unstructured or semi-structured content. Applications access it using the OASIS standard protocol Content Management Interoperability Services (CMIS).

Document Service Sample App


The following example will enable the document store to be browsed and modified from a Kapsel app.

  • Replace Replace www\index.html with
    <!DOCTYPE html>
    <html>
    <head>
    <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
    <script type="text/javascript" charset="utf-8" src="serverContext.js"></script>
    <script type="text/javascript" charset="utf-8" src="cordova.js"></script>
    <!--Required by Document Service-->
    <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
    <script src="https://svn.apache.org/repos/asf/chemistry/parts/trunk/cmis-js/lib/cmis.js"></script>
    <script>
    var applicationContext = null;

    window.onerror = onError;

    function onError(msg, url, line) {
    var idx = url.lastIndexOf("/");
    var file = "unknown";
    if (idx > -1) {
    file = url.substring(idx + 1);
    }
    alert("An error occurred in " + file + " (at line # " + line + "): " + msg);
    return false; //suppressErrorAlert;
    }

    function init() {
    updateStatus1("Calling Logon.init");

    if (sap.Logger) {
    sap.Logger.setLogLevel(sap.Logger.DEBUG); //enables the display of debug log messages from the Kapsel plugins.
    sap.Logger.debug("EventLogging: Log level set to DEBUG");
    }

    if (navigator.notification) { // Override default HTML alert with native dialog. alert is not supported on Windows
    window.alert = navigator.notification.alert;
    }

    sap.Logon.init(logonSuccessCallback, logonErrorCallback, appId, context);
    console.log("EventLogging: init completed");
    }

    function logonSuccessCallback(result) {
    updateStatus1("logonSuccessCallback called");

    console.log("EventLogging: logonSuccessCallback " + JSON.stringify(result));
    applicationContext = result;
    connectCMIS("/");
    showScreen("MainDiv");
    }

    function logonErrorCallback(error) { //this method is called if the user cancels the registration.
    alert("An error occurred: " + JSON.stringify(error));
    if (device.platform == "Android") { //Not supported on iOS
    navigator.app.exitApp();
    }
    }

    function errorCallback(e) {
    alert("An error occurred: " + JSON.stringify(e));
    console.log("EventLogging: errorCallback " + JSON.stringify(e));
    showScreen("MainDiv");
    }

    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 updateStatus1(msg) {
    document.getElementById('statusID').innerHTML = msg + " ";
    console.log("EventLogging: " + msg + " ");
    }

    function addZero(input) {
    if (input < 10) {
    return "0" + input;
    }
    return input;
    }

    function onLoad() {
    console.log("EventLogging: onLoad");
    var fileUpload = document.getElementById("file");
    fileUpload.onchange = function(e) { //trigger the logic to get a name of the selected file and start to upload the image after something was selected with the file input element.
    uploadImage();
    }
    }

    function onPause() {
    console.log("EventLogging: onPause");
    }

    function onResume() {
    console.log("EventLogging: onResume");
    }

    function onSapResumeSuccess() {
    console.log("EventLogging: onSapResumeSuccess");
    }

    function onSapLogonSuccess() {
    console.log("EventLogging: onSapLogonSuccess");
    }

    function onSapResumeError(error) {
    console.log("EventLogging: onSapResumeError " + JSON.stringify(error));
    }

    document.addEventListener("deviceready", init, false);
    document.addEventListener("pause", onPause, false);
    document.addEventListener("resume", onResume, false);
    document.addEventListener("onSapResumeSuccess", onSapResumeSuccess, false);
    document.addEventListener("onSapLogonSuccess", onSapLogonSuccess, false);
    document.addEventListener("onSapResumeError", onSapResumeError, false);

    //CMIS
    var cmisURL;
    var session;
    var rootObject;
    var myfileId;
    var currentFolder;

    // Establish a connection with the Document Service
    // and try to download the image of the product
    function connectCMIS(fname) {
    cmisURL = "https://" + applicationContext.registrationContext.serverHost + "/mobileservices/persistence/v1/json/" + appId;
    session = cmis.createSession(cmisURL + "/$metadata?rand=" + Math.random());

    session.setCredentials(applicationContext.registrationContext.user, applicationContext.registrationContext.password).loadRepositories( {
    request : {
    success : function(data) {
    updateStatus1("Connected to Document Service ");
    //once the connection has been established, it gets the root object
    getRootObject(fname);
    },
    error : function(e) {
    if (e.responseJSON)
    console.log( "Error during the request: " + e.responseJSON.message);
    else
    console.log( "Error during the request: " + e.statusText);
    }
    }
    });
    }

    //Gets a reference to the root directory to be able to navigate through the repository
    function getRootObject(fname) {
    session.getObjectByPath("/", {
    includeRelationships : 'both',
    request : {
    success : function(data) {
    console.log("Get Object By Path: SUCCESS");
    console.log("Get Object By Path", JSON.stringify(data));
    rootObject = data;
    console.log("Root:"+ data.properties['cmis:name'].value +" "+ data.properties['cmis:objectId'].value);
    currentFolder = "/";
    //Once the root directory is accessible, it tries to download
    //an image associated with the product name
    //showPictureByName(fname);

    },
    error : function(e) {
    console.log("Error during the request: " + e.responseJSON.message);
    }
    }
    });
    }

    //Ask the user to enter a name, search for it in the current diretory and if found display on the screen
    function showPictureByName() {
    setImageProperties("ProductImg", true, ""); //clear any previously displayed picture by setting the URL to empty.
    navigator.notification.prompt(
    'Enter the name of the image to show', // message
    onPrompt, // callback to invoke
    'Show Image', // title
    ['Ok','Exit'], // buttonLabels
    '' // defaultText
    );

    function onPrompt(results) {
    if (results.buttonIndex == 1) {
    updateStatus1("Attempting to show image " + results.input1);
    var randParam = "?rand=" + Math.random();
    var url = "https://" + applicationContext.registrationContext.serverHost + "/mobileservices/persistence/v1/json/" + appId + currentFolder;
    var xmlhttp = new XMLHttpRequest();

    xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4) {
    if (xmlhttp.status == 200) {
    var children = obj = JSON.parse(this.responseText);
    for (var i = 0; i < children.objects.length; i++) {
    if (children.objects[i].object.properties['cmis:objectTypeId'].value == "cmis:document") {
    if (children.objects[i].object.properties['cmis:name'].value == results.input1) {
    var url2 = cmisURL + "?objectId="+children.objects[i].object.properties['cmis:objectId'].value +"&cmisselector=content";
    setImageProperties("ProductImg", true, url2);
    updateStatus1(results.input1 + " displayed");
    break;
    }
    }
    if (i == children.objects.length - 1) {
    updateStatus1("Image " + results.input1 + " not found");
    }
    }
    if (children.objects.length == 0) {
    updateStatus1("No images found");
    }
    }
    }
    }

    xmlhttp.open("GET", url + randParam, true);
    xmlhttp.setRequestHeader("Accept", "application/xml"); //setting this so it is easier to view response in Network > Preview tab.
    xmlhttp.send();
    }
    }

    }

    //Ask the user to enter a name, delete it from the current diretory
    function deletePictureByName() {
    setImageProperties("ProductImg", false, ""); //clear any previously displayed picture by setting the URL to empty.
    navigator.notification.prompt(
    'Enter the name of the image to delete from the current folder', // message
    onPrompt, // callback to invoke
    'Delete Image', // title
    ['Ok','Exit'], // buttonLabels
    '' // defaultText
    );

    function onPrompt(results) {
    if (results.buttonIndex == 1) {
    updateStatus1("Attempting to delete image " + results.input1);
    var randParam = "?rand=" + Math.random();
    var url = "https://" + applicationContext.registrationContext.serverHost + "/mobileservices/persistence/v1/json/" + appId + currentFolder;
    var xmlhttp = new XMLHttpRequest();

    xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4) {
    if (xmlhttp.status == 200) {
    var children = obj = JSON.parse(this.responseText);
    for (var i = 0; i < children.objects.length; i++) {
    if (children.objects[i].object.properties['cmis:objectTypeId'].value == "cmis:document") {
    if (children.objects[i].object.properties['cmis:name'].value == results.input1) {
    updateStatus1("Calling Delete on " + session.deleteObject(children.objects[i].object.properties['cmis:objectId'].value));
    session.deleteObject(children.objects[i].object.properties['cmis:objectId'].value, true /*, options*/);
    refreshList();
    break;
    }
    }
    if (i == children.objects.length - 1) {
    updateStatus1("Image " + results.input1 + " not found");
    }
    }
    if (children.objects.length == 0) {
    updateStatus1("No images found");
    }

    }
    }
    }

    xmlhttp.open("GET", url + randParam, true);
    xmlhttp.setRequestHeader("Accept", "application/xml"); //setting this so it is easier to view response in Network > Preview tab.
    xmlhttp.send();
    }
    }
    }

    //Create an image in the repository
    function uploadImage() {
    console.log("trying to get picture");
    var file = document.getElementById("file").files[0];
    navigator.notification.prompt(
    'Enter the name of the image', // message
    onPrompt, // callback to invoke
    'Image Name', // title
    ['Ok','Exit'], // buttonLabels
    file.name // defaultText
    );

    function onPrompt(results) {
    if (results.buttonIndex == 1) {
    var fname = results.input1;
    var file = document.getElementById("file").files[0];
    uploadFile(file, fname);
    }
    var fileUpload = document.getElementById("file");
    fileUpload.value = ""; //if not set, unable to upload the same image twice.
    }
    }

    function uploadFile(file, filename) {
    var folderId = rootObject.properties['cmis:objectId'].value;

    session.createDocument(folderId, file, filename , "image/jpeg", "major", null, null, null, {
    request : {
    success : function(data) {
    myfileId = data.properties["cmis:objectId"].value;
    console.log( "Create Document: SUCCESS");

    //upload content
    session.setContentStream(myfileId, file, true, "image/jpeg", {
    request : {
    success : function(data) {
    fileId = data.properties["cmis:objectId"].value;
    console.log("Set Content Stream: SUCCESS");
    updateStatus1("Uploaded " + filename);
    refreshList();
    },
    error : function(e) {
    updateStatus1("Failed to upload image: " + e.statusText);
    }
    }
    });
    },
    error : function(e) {
    updateStatus1("Failed to upload image: " + e.statusText);
    }
    }
    })
    }

    function showPictureById(fileId){
    var url = cmisURL + "?objectId=" + fileId + "&cmisselector=content";
    setImageProperties("ProductImg", true, url);
    }

    function setImageProperties(id, visible, url) {
    var img = document.getElementById(id);
    img.style.visibility = (visible ? 'visible' : 'hidden');
    img.src = url;
    }

    //Allows lists the files of the root of the repository or one level deep folder.
    function listFiles(subFolderToOpen, previousFolder) {
    updateStatus1("Updating File List");
    setImageProperties("ProductImg", false, "");
    var sfToOpen = subFolderToOpen;

    if (previousFolder == undefined) {
    previousFolder = "";
    }
    if (sfToOpen == undefined) {
    sfToOpen = "";
    }
    else if (subFolderToOpen == "..") { //goback one level
    previousFolder = previousFolder.substring(0, previousFolder.lastIndexOf("/"));
    sfToOpen = "";
    }
    var randParam = "?rand=" + Math.random();
    var url = "https://" + applicationContext.registrationContext.serverHost + "/mobileservices/persistence/v1/json/" + appId + "/" + previousFolder + '/' + sfToOpen;
    var xmlhttp = new XMLHttpRequest();

    xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4) {
    if (xmlhttp.status == 200) {
    var children = obj = JSON.parse(this.responseText);
    var prevFolder = "";
    if (previousFolder) {
    prevFolder = previousFolder;
    }
    if (sfToOpen) {
    prevFolder = prevFolder + "/" + sfToOpen;
    }

    var str = '';
    //decide when to include a .. to navigate back.
    if (subFolderToOpen == undefined || (subFolderToOpen == ".." && previousFolder == "")) {
    str = '<ul>';
    }
    else {
    var deleteIndex = prevFolder.lastIndexOf("/");
    var url3 = prevFolder.substring(0, deleteIndex);
    str = '<ul><li><a href="javascript:void(0)" onclick="getObject(\'' + url3 + '\'); listFiles(\'..\', \'' + prevFolder + '\')">.. (Folder)</a></li>';
    }

    for (var i = 0; i <children.objects.length; i++) {
    if (children.objects[i].object.properties["cmis:baseTypeId"].value == 'cmis:folder') {
    var folderName = children.objects[i].object.properties["cmis:name"].value;
    var url2 = prevFolder + '/' + folderName;
    str += '<li><a href="javascript:void(0)" onclick="getObject(\'' + url2 + '\'); listFiles(\'' + folderName + '\', \'' + prevFolder + '\')">' + folderName + ' (Folder)</a></li>';

    } else {
    var name = children.objects[i].object.properties["cmis:name"].value;
    str += '<li><a target= "_blank" href="' + url + "/" + name + randParam + '">' + name + '</a></li>';
    }
    }
    str += "</ul>";
    document.getElementById("listID").innerHTML = str;
    updateStatus1("File List Updated");
    }
    else {
    updateStatus1("Request to List files returned " + xmlhttp.status);
    }
    }
    }

    xmlhttp.open("GET", url + randParam, true);
    xmlhttp.setRequestHeader("Accept", "application/xml"); //setting this so it is easier to view response in Network > Preview tab.
    xmlhttp.send();
    }

    function getObject(path) {
    if (path == "") {
    path = "/";
    }
    session.getObjectByPath(path, {
    includeRelationships : 'both',
    request : {
    success : function(data) {
    console.log("Get Object By Path: SUCCESS");
    console.log("Get Object By Path", JSON.stringify(data));
    rootObject = data;
    console.log("Root:"+ data.properties['cmis:name'].value +" "+ data.properties['cmis:objectId'].value);
    currentFolder = path;
    },
    error : function(e) {
    console.log("Error during the request: " + e.responseJSON.message);
    }
    }
    });
    }

    function refreshList() {
    if (currentFolder.length == 1) {
    listFiles();
    } else {
    var lastSlash = currentFolder.lastIndexOf("/");
    var subFolderToOpen = currentFolder.substring(lastSlash + 1);
    var previousFolder;
    if (lastSlash == 0) {
    previousFolder = "";
    } else {
    previousFolder = currentFolder.substring(0, lastSlash);
    }
    listFiles(subFolderToOpen, previousFolder);
    }
    console.log("Current Folder: " + currentFolder);
    }

    </script>
    </head>
    <body onLoad="onLoad()">
    <div class="screenDiv" id="LoadingDiv">
    <h1>Loading ...</h1>
    </div>
    <div class="screenDiv" id="MainDiv" style="display: none">
    <h2>Document Service Sample</h2>
    <span id="statusID"></span><br>
    <hr>
    <button onClick="listFiles(); getObject('/')">List Files</button>
    <button id="showImage" onClick="showPictureByName()">Show Image</button>
    <input type="file" id="file" accept="image/*" style="display:none;"></input>
    <input type="button" id="loadFile" value="Upload Image" onclick="document.getElementById('file').click();" />
    <button id="deleteImage" onClick="deletePictureByName()">Delete Image</button>
    <span id="listID"></span><br>
    <img id="ProductImg" height="100" width="100" src="" style="float: none;visibility: hidden"><br>
    </div>
    <div class="screenDiv" id="UploadDiv" style="display: none">
    </div>
    </body>
    </html>​


  • Add the attachment viewer plugin.
    cordova plugin add kapsel-plugin-attachmentviewer --searchpath %KAPSEL_HOME%/plugins
    or
    cordova plugin add kapsel-plugin-attachmentviewer --searchpath $KAPSEL_HOME/plugins


  • If deploying to iOS, edit the plist file and add the following entry.
    <key>NSPhotoLibraryUsageDescription</key>
    <string>Upload images to the SAP Cloud Platform Document Service</string>
    <key>NSCameraUsageDescription</key>
    <string>Upload images to the SAP Cloud Platform Document Service</string>


  • Prepare, build and deploy the app with the following command.
    cordova run android
    or

    cordova run ios

    or
    cordova run windows -- --archs=x64

    or
    cordova run windows --device -- --archs=arm --phone



  • Click on Upload Image to upload an image to the document store.

    Note the android.png link can be clicked on to open the image in a new window or it can be shown on the same page using the Show Image button.

  • The SAP Cloud Platform Mobile Services cockpit enables the browsing and modifying of the document service.  Each application has its own document service.
    Click on Mobile Applications -> Native/Hybrid.
    Choose the application you want to add the Document Service to. On the Assigned Features list, click on the add symbol on the top right. Add the Document Repository feature.

    Note, it is possible to create a set of folders and sub-folders with the management cockpit UI.


Previous   Home