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: 

In today's post, we are going to get our hands dirty on the Document Service of HANA Cloud and Apache Chemistry OpenCMIS library.

What is CMIS?

From Wiki:

Content Management Interoperability Services (CMIS) is an open standard that allows different content management systems to inter-operate over the Internet.[1] Specifically, CMIS defines an abstraction layer for controlling diverse document management systems and repositories using web protocols.

and what is HANA Cloud Document Service?

From HANA Cloud Platform Documentation:

The SAP HANA Cloud document service 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). Applications running on SAP HANA Cloud can easily consume the document service using the provided client library. Since the document service is exposed using a standard protocol, it can also be consumed by any other technology that supports the CMIS protocol.

Basically the usual way of using the document service is right from your web application that runs on the HANA Cloud platform but in this example, we are going to talk to the Document Service directly from our mobile device. I followed this tutorial to quickly get started. So the idea is to have a Proxy Bridge in between that will relay our CMIS requests to the Document Service. This diagram explains the idea clearly:

https://help.hana.ondemand.com/help/7611b207711e1014839a8273b0e91070.image

Creating the Proxy Bridge

So we just need to create a servlet that extends AbstractCmisProxyServlet and everything's good to go and should look like this:

public class CMISProxyServlet extends AbstractCmisProxyServlet {
   @Override
   protected String getRepositoryUniqueName() {
       return "MySampleRepository";
   }
   @Override
   //For productive applications, use a secure location to store the secret key.
   protected String getRepositoryKey() {
       return "abcdef0123456789";
   }
}

One thing I noticed after running this is that, the repository needs to be created first which I thought is already being handled for you by the AbstractCmisProxyServlet. So we need to add the repository initialization code in the servlet's init method.

public class CMISProxyServlet extends AbstractCmisProxyServlet {
          private static final long serialVersionUID = 1L;
          /*
           * (non-Javadoc)
           *
           * @see javax.servlet.GenericServlet#init()
           */
          @Override
          public void init() throws ServletException {
                    super.init();
                    RepositoryOptions options = new RepositoryOptions();
                    options.setUniqueName(getRepositoryUniqueName());
                    options.setRepositoryKey(getRepositoryKey());
                    options.setVisibility(Visibility.PROTECTED);
                    InitialContext ctx = null;
                    try {
                              ctx = new InitialContext();
                              String lookupName = "java:comp/env/" + "EcmService";
                              EcmService ecmSvc = (EcmService) ctx.lookup(lookupName);
                              ecmSvc.createRepository(options);
                    } catch (NamingException e) {
                              e.printStackTrace();
                    }
          }
          /*
           * (non-Javadoc)
           *
           * @see com.sap.ecm.api.AbstractCmisProxyServlet#getRepositoryKey()
           */
          @Override
          protected String getRepositoryKey() {
                return "uniqueRepoKey"
          }
          /*
           * (non-Javadoc)
           *
           * @see com.sap.ecm.api.AbstractCmisProxyServlet#getRepositoryUniqueName()
           */
          @Override
          protected String getRepositoryUniqueName() {
                    return "uniqueRepoName";
          }
          /*
           * (non-Javadoc)
           *
           * @see com.sap.ecm.api.AbstractCmisProxyServlet#supportAtomPubBinding()
           */
          @Override
          protected boolean supportAtomPubBinding() {
                    return true;
          }
}

and in web.xml, we need to add a reference to EcmService which is part of the Document Service API and is responsible for setting up our repository.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <servlet>
    <servlet-name>cmisproxy</servlet-name>
    <servlet-class>com.sap.sapfiledepot.CMISProxyServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>cmisproxy</servlet-name>
    <url-pattern>/cmis/*</url-pattern>
  </servlet-mapping>
  <resource-ref>
    <res-ref-name>EcmService</res-ref-name>
    <res-type>com.sap.ecm.api.EcmService</res-type>
  </resource-ref>
</web-app>

After that, just follow the usual steps in deploying your web application to HANA Cloud either through Eclipse or through command line. Now we're ready to develop our mobile application.

Creating the Mobile Application

The application's purpose is simple, to be able to upload any kind of files from user's sdcard, create folders and sub-folders as well as delete and download the files to the mobile device for viewing. There will be simple login screen to enter the credentials, account name and also select from  trial hana server or production server.

The main screen will contain a Grid View of all the items of the current folder. Initial folder will be the root folder. There will be 2 buttons below to create a new directory and upload a new document respectively.

The user can click on the folder icons to traverse it or click on the non-folder icons to view the content. Users can also long press on each icon and they can choose whether to delete the selected item or view the properties.

Let's Dive into Code

In order for us to be able to talk to the Document Service API, we need to use Apache Chemistry OpenCMIS client library for Java.

Get it from here: http://chemistry.apache.org/java/opencmis.html

Just drop the library into your libs folder and you're good to go. The Apache Chemistry OpenCMIS library is dependent on the slf4j library so we also need to get that one and drop it into the libs folder. Download the binary here that's specific for Android:

http://www.slf4j.org/android/

Let's look at some of the common functionalities that we are going to use for our application:

Login and Creation of Session

public static Session login(String username, String password, String url) throws RepositoryNotFoundException {
                    SessionFactory sessionFactory = SessionFactoryImpl.newInstance();
                    Map<String, String> parameter = new HashMap<String, String>();
                    parameter.put(SessionParameter.USER, username);
                    parameter.put(SessionParameter.PASSWORD, password);
                    parameter.put(SessionParameter.ATOMPUB_URL, url);
                    parameter.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
                    List<Repository> repositories = sessionFactory.getRepositories(parameter);
                    if (repositories.size() > 0) {
                              return repositories.get(0).createSession();
                    }
                    throw new RepositoryNotFoundException();
          }

The login method will return a session object that we will use all throughout in the application. The ATOMPUB_URL is the CMIS endpoint exposed by the proxy bridge. In our example, the web app root context is pointing to https://sapfiledepoti071571trial.hanatrial.ondemand.com/SAPFileDepot. The endpoint will be pointing to https://sapfiledepoti071571trial.hanatrial.ondemand.com/SAPFileDepot/cmis/atom/.

Deleting a Document

public static void deleteDocument(Document document, boolean deleteAllVersions) {
                    document.delete(deleteAllVersions);
     }

Deleting a document is as easy as calling this single-liner in which you have the option to either just to delete only the specific version of document being deleted or delete away all the versions of the document.

Creating a New Folder

public static Folder createFolder(Folder parent, String folderName) {
                    if (folderName == null || folderName.trim().length() == 0) {
                              throw new IllegalArgumentException("folderName cannot be empty");
                    }
                    Map<String, Object> properties = new HashMap<String, Object>();
                    properties.put(PropertyIds.OBJECT_TYPE_ID, "cmis:folder");
                    properties.put(PropertyIds.NAME, folderName);
                    return parent.createFolder(properties);
          }

Each folder needs to have a parent and we just need to specify the folder name in order to create it. It will return the newly created folder afterwards.

Creating/Uploading a Content

There are actually two steps involved when creating a new document. First, you need to create a ContentStream object by calling session.getObjectFactory().createContentStream method. You just need to pass the filename, mime type, the length of the file and finally the inputstream representing the file to be uploaded.

public static ContentStream createContentStream(Session session, String fileName, String mimeType, long len, InputStream input) {
                    return session.getObjectFactory().createContentStream(fileName, len, mimeType, input);
          }

After that, you can now call Folder.createDocument passing the contentStream that you've just created and some the simple property that defines the filename of the document.

public static Document createContent(Session session, Folder parent, String fileName, ContentStream contentStream) throws CmisBaseException {
                    Map<String, Object> properties = new HashMap<String, Object>();
                    properties.put(PropertyIds.OBJECT_TYPE_ID, "cmis:document");
                    properties.put(PropertyIds.NAME, fileName);
                    Document doc = parent.createDocument(properties, contentStream, VersioningState.MAJOR);
                    return doc;
          }

That's all that we need to do and if you want to checkout the source code of the app, head over to my github page https://github.com/mharkus/FileDepot. You can also watch the video of the app below:

If you want to read more about the HANA Cloud Document Service, go to:

https://help.hana.ondemand.com/help/frameset.htm?e60b7e45bb57101487a881c7c5487778.html

If you need a robust and easy way to manage files or documents in your mobile applications, you may want to take advantage of the HANA Cloud Document Service.

Thanks for dropping by.

1 Comment