Skip to Content

Introduction

I’ve been working on a project to bring the major elements of SAP mobility together in a single example. This example will explore the details of creating a delta-enabled OData web service, something that I mentioned in my last blog post.

At the end of the project we’ll have this:

  • A web service that supports OData Delta Token processing
  • A Hybrid Kapsel application created using Web IDE that uses that service
  • Support for disconnected operation in the mobile app using the SMP SDK’s Offline capabilities
  • Support for adding and editing records in the mobile app
  • Run both the web service and mobile application atop the HANA Cloud Platform

The end result would nicely tie UI5, Web IDE, and HCP Mobile Services together into an offline-ready Hybrid mobile application.

Walking through the steps will require a bit of effort.  I plan to break it up into several articles, each covering one segment.  My goal is to have each article small enough to complete in an hour or less.

So, where to start?

Part 1 – A Delta-Token-Enabled OData Web Service

HANA Cloud Platform Trial Account – with Mobile Services

If you don’t already have a HANA Cloud Platform trial account, you can register for an account using this link.

HANA Cloud Platform Mobile Services, abbreviated HCPms, is now available as part of your HANA trial account, too.  You can review the instructions in Martin Grasshoff’s recent blog post for information on how to add HCPms to your HCP trial account.

You will need to sign up for both to complete this series of articles.

Build an OData Web Service

I’ve been working extensively in the past months with Apache Olingo, an open source OData web services framework.  I have come to like Olingo quite a lot.  I find it well organized and reliable, so I’m going to use it in this example to generate our OData web service.

The Data Model

The techniques that I’ll apply in this article can be used with almost any JDBC-compatible backing data storage.  For this project, though, I have chosen to start with a variant of SAP’s Enterprise Sales and Procurement Model (ESPM).  ESPM is a business data model widely used in examples in many current SAP programming systems.

You can find a number of articles on SCN describing different variants of ESPM.  Some use HANA as a back-end, some use other databases.  This particular variant is one that I created using the Java Persistence Architecture (JPA) to define the data model.  Olingo provides several ways to define an OData web service — it has a particularly easy set of APIs for doing that if your starting point is JPA, so that’s why I’m using that here.

The diagram below depicts the entity relationship diagram for this version of the ESPM data model.

ESPM-ERD.png

Configure Your Java Development Environment

The complete source code to our web service is available on Github.  Here’s a few simple steps that you can follow to import, build, and run the service on your local machine.  We’ll deploy it to your local machine first.  Later, we’ll deploy a copy of the same service to a HANA Cloud Platform Java application server.


  1. If you have not already, install the Eclipse JEE Edition of Eclipse Kepler or Luna and the HCP Development plugins for it.  The installation guide I recently used can be found here – that document contains more information than we really care about for our purposes – limit the instructions you follow to steps 1.1 through 1.6 [NOTE: these steps install JDK, Eclipse, & Maven on your local machine; you can safely stop at completion of the step in 1.6 labelled “Check Maven User Settings”].
  2. Import the ESPM Olingo git repository as a Maven project

    (2.a) Start Eclipse
    (2.b) Import the project from Github –
    Click “File>Import”, Select “Maven>Check out Maven projects from SCM”, Click “Next”

    Screen Shot 2015-01-14 at 4.05.04 PM.png
    (2.c) Import (continued) –
    Select “git” as the SCM system of choice; enter “https://github.com/SAP/sap_mobile_platform_espm_olingo_services.git” as the SCM URL; click “Finish”;  The import will take a moment.  At the end of the import, your Project Explorer should contain an ESPM_V1 project:

    Screen Shot 2015-01-14 at 4.12.22 PM.png

  3. Build the ESPM web services application
    — Right-click on the ESPM_V1 project in the Project Explorer window, select “Run As>Maven Build…”. You should see a dialog that looks like this one below.  Enter “clean install” in the Goals field.  Press “Run”.

    Screen Shot 2015-01-06 at 6.04.11 PM.png

    Under normal conditions the Eclipse Console window will indicate the build succeeded with a message similar to this:

    Screen Shot 2015-01-06 at 6.12.48 PM.png

  4. Download a copy of the Tomcat 7 server binary distribution .ZIP file I used 7.0.57, but almost any Tomcat 7 version will do.
  5. Create a new Tomcat server instance in your Eclipse workspace by following these instructionsfrom the Eclipse documentation set.
  6. Run the project on your newly created Tomcat server –  Right-click on the ESPM_V1 project and select “Run As…>Run on Server”.  You will see something like the dialog show below.  Select the “tomcat 7.0 server at localhost” and click “Finish”.

    Screen Shot 2015-01-06 at 6.01.47 PM.png

  7. Verify the application runs correctly by visiting this link in your web browser: http://localhost:8080/ESPM_V1/api/Products

If the application was deployed correctly, you will see an XML representation of about 110 products.  The web service is programmed to install a collection of test data for Products, Stock, Suppliers, and Customers.  Each time the application is restarted, it will drop and reinitialize those tables in the database (you can change the behavior to preserve the state of the database between invocations by changing the eclipselink.ddl-generation property in src/main/resources/WEB-INF/persistence.xml from “drop-and-create-tables” to “create-tables“).

If you scroll to the bottom of the Products response, you will see something like this:

Screen-Shot-2015-01-07-at-9.46.32-PM.png

As you can see, there is an UpdatedTimestamp field associated with each record.  Because our code supplied a delta token generator, there is a “delta” link URL at the bottom of the response.

OData Delta Tokens

The OData protocol is essentially a superset of a standard RESTful web service.  One of the really cool extensions to REST supplied by OData is Delta Token handling. Using Delta tokens affords more efficient communications between each client and the source web service (OASIS design document reference).

SAP’s Mobile Platform products – both cloud and on-premise versions – will leverage a delta token enabled web service to optimize data synchronization.  I recently wrote an article describing the mechanics of this process — it might be worth your time to review it (link).  The point here is that we want the most scalable web service possible, so we’ll take the extra steps required to enable delta token processing for most of this service’s OData entity collections.

Apache Olingo provides a couple of framework-based options for adding delta token support to JPA-based projects.  I used the first of the two options documented in the Olingo on-line documentation.  To reconfigure the project to use that approach, I first added an “updated timestamp” column to each table where I wanted to add delta token support.  I then added or modified the JPA @PrePersist and @PreUpdate methods to automatically update this updatedTimestamp field with the current server time for both of these operations.  Finally, I created the ESPMJPADeltaListener class based on ODataJPATombstoneEntityListener, as described in the Olingo documentation.

Adding the “updated timestamp” column follows a common pattern of leveraging server timestamps to track what changes between requests.  In the implementation of the ESPMJPADeltaListener class, I set up the delta token generator to return a server timestamp.  This timestamp will be returned as part of the request contents.


public class ESPMJPADeltaListener extends ODataJPATombstoneEntityListener {
 static final String DATEFORMAT = "yyyy-MM-dd HH:mm:ss";
 /*
  * Generate a web-service-specific delta token to be passed back to the
  * client with a response.  In this case, we simply generate an ISO-8601-style
  * string reflecting the current UTC date/time.
  * @see org.apache.olingo.odata2.jpa.processor.api.ODataJPATombstoneEntityListener#generateDeltaToken(java.util.List, javax.persistence.Query)
  */
 @Override
  public String generateDeltaToken(List<Object> deltas, Query query) {
  final SimpleDateFormat sdf = new SimpleDateFormat(DATEFORMAT);
      sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
      final String utcTime = sdf.format(new Date());
      return utcTime;
  }





The getQuery() method is a bit more complex, but the core functionality is found below.  Basically, if the client supplies a delta token as part of the GET request, the function with modify the SQL data fetched to be limited to rows that changed after the timestamp supplied in the delta token.  The client will not have a delta token to supply on the initial request — and some applications may not want to leverage delta tokens at all.  In both of those cases the code responds to the missing delta token by returning a complete set of data results.

 


String deltaToken = ODataJPATombstoneContext.getDeltaToken();
  Query query = null;
  if (deltaToken != null) {
       String statement = jpqlStatement.toString(); 
       String[] statementParts = statement.split(JPQLStatement.KEYWORD.WHERE); 
       String deltaCondition = jpqlContext.getJPAEntityAlias() + ".updatedTimestamp >= {ts '" + deltaToken + "'}"; 
       if (statementParts.length > 1) 
       {   
            statement = statementParts[0] + JPQLStatement.DELIMITER.SPACE + JPQLStatement.KEYWORD.WHERE +                JPQLStatement.DELIMITER.SPACE + deltaCondition + JPQLStatement.DELIMITER.SPACE + JPQLStatement.Operator.AND +                statementParts[1]; 
       } 
       else {   
            statement = statementParts[0] + JPQLStatement.DELIMITER.SPACE + JPQLStatement.KEYWORD.WHERE + JPQLStatement.DELIMITER.SPACE + deltaCondition; 
       }
       query = em.createQuery(statement);
  }
  else  {
       query = em.createQuery(jpqlStatement.toString());
  }
  return query;





You can see delta tokens in action by copying the entire contents of the delta token’s “href” attribute from step 7 and pasting that into your browser URL box. You will see a different response this time — one that does not include any records, since nothing has been changed since the original request was issued.

Deploy the Web Service to your HCP Trial Account

For simplicity’s sake, I chose to store my ESPM data in an embedded Java-based SQL engine, Hypersonic. You could do the same thing in HANA, but the extra steps involved to do that would not really be relevant to our example.  To wrap up this exercise, we’ll deploy the ESPM web service onto a HANA Cloud Platform app server using your trial account.

Your HANA Trial includes the capability to deploy one small sized Java application at no charge (this is a ‘micro’ instance in AWS terms).  Unless you have been working with Java in HCP, your probably have not taken advantage of this resource yet.  If it happens that you have, you will need to stop any Java applications you are running to deploy our ESPM application.

  1. Deploy the application using Eclipse — A deployment to the HANA Cloud Platform Java server is performed in much the same way that your deployed to your local Tomcat instance.  Start by right-clicking on the ESPM_V1 project and select “Run>Run on Server…”.

    Screen Shot 2015-01-07 at 7.51.36 PM.png

    Select “Manually Create a new Server” and choose the Server Type as “SAP>SAP HANA Cloud Platform”.

    Enter “hanatrial.ondemand.com” as the Landscape host.

    Click “Next”.

    Screen Shot 2015-01-07 at 9.36.18 PM.png

    Enter “espm” as the Application name (for some reason, HCP insists that this name be all lower case with no symbol characters).

    For Account Name, enter your SAP S/C/I/D-Number followed by “trial” (no spaces or other punctuation).

    For User Name, enter your SAP S/C/I/D-Number.

    Enter your password.

    I found that I had to uncheck “Save Password” to get this to work correctly on OS X.  You may start with it “checked” if you like and then uncheck it if the operation fails (the only consequence I experienced was having to re-enter my password a few extra times).

    Click ‘Finish’.

    The deployment will take several minutes to complete.  You can move on to Step 2 to monitor the status of the deployment and to prepare to test the deployed service.

  2. Check the deployment in the HANA Cloud Platform Cockpit — In your browser, open the HANA Cloud Platform Cockpit.

    Click “Java Applications” on the left hand bar.

    You will see something like the screen below, although most of the Actions (start, Stop, Switch, and Update) will be disabled (greyed-out) until the deployment completes.  You can refresh the page to monitor the deployment status.

    Once all the Action buttons are enabled. We’re ready to move on to Step 3.

    Click on “espm” in the Name column to continue.
    Screen Shot 2015-01-07 at 9.44.24 PM.png

  3. Test the ESPM web service — The details page on the “espm” application will include a link to the “Application URL” (below)

    Screen Shot 2015-01-07 at 9.45.06 PM.png

    Click the Application URL link.  You will see a details form looking something like this:

    Screen Shot 2015-01-07 at 9.46.03 PM.png

    Append “api/Products” to the URL and press “Go” or Enter. 

    The end result should be the same response you saw with your local Tomcat service.

Summary

This ends the first section of our four part project.  If all went according to plan, you have successfully deployed your Olingo-based web service into the HANA Cloud Platform.  You also now have your machine configured to expand your exploration of Java applications that are deployable to the HCP landscape.

In the next article in this series, we’ll explore how to use HCP’s Web IDE and other elements of the SAP Mobile Platform to build a Hybrid mobile application that accesses this service.

To report this post you need to login first.

9 Comments

You must be Logged on to comment or reply to a post.

  1. Martin Grasshoff

    Hi Riley,

    this is cool stuff. It’s nice to see how open HCP is and that Delta-Tokens are not rocket science.

    Looking forward to see the next articles.

    -Martin

    (0) 
  2. SIMMACO FERRIERO

    Hi Riley,

    I’ve a strange question for you. I’m using this data source for my application, but I’m not able to create a valid payload to add the supplier to a product when creating a new product: the new product is created successfully, but it comes without Supplier. Here it is the payload I think should work, but it doesn’t:

    {

      “ProductId”:”AA-1001″,

      “Name”:”pendrive”,

      “ShortDescription”:”pendrive”,

      “CurrencyCode”:”EUR”,

      “Price”:”100″,

      “PictureUrl”:”PF-1000.jpg”,

      “Supplier”:{

        “__metadata”:{

          “uri”:”/Suppliers(‘100000041’)”

        }

      }

    }

    I’m also attaching the proof that whenever I select the new product in the app, the supplier is not present.

    /wp-content/uploads/2015/04/response_678707.png

    Another strange thing is that if I do the same with another OData source like

    http://services.odata.org/V2/%28S%28scnforumblogpost%29%29/OData/OData.svc/$metadata

    it works fine.

    Do you know which is the correct payload I’ve to use for associating a valid existing supplier to a new product?

    Thanks and regards,

    Simmaco

    (0) 
  3. Gregor Wolf

    Dear Riley,

    thank you for providing this great example. Even I as an ABAP Developer was able to deploy this Java App successfully on my HANA Trial account. But I have one issue regarding the persistence you mention to change

    the eclipselink.ddl-generation property in src/main/resources/WEB-INF/persistence.xml from “drop-and-create-tables” to “create-tables”).

    But what I’ve found in the persistence.xml on GitHub is only  “drop-and-create” I’ve tried to replace this with “create”, rebuilt the app, deployed on HCP and restarted the app. When I then create a new product I can read this product again. But when I execute another restart of the app then the product is gone. Hope you can help there.

    Best regards

    Gregor

    (0) 
    1. Riley Rainey Post author

      Hi Gregor,

      I configured this project intending it to be as lightweight as possible. Based on that, I used Hypersonic rather than HANA or ASE for its data storage. Hypersonic is a simple Java-based SQL database. As configured, the Hypersonic database file storage is located in the application server instance.  I am wondering if that might be deleted if the instance is restarted in HCP. I don’t think that used to be the case, but perhaps something has changed.

      To be clear, the correct DDL generation setting in persistence.xml should be:

        <property name=“eclipselink.ddl-generation” value=“create-tables”></property>


      The quickest way to ensure long term persistence here might be to switch the project from using Hypersonic to using HANA.  Coincidentally, I am working on an example project that is configured that way: take a look at this persistence.xml file: cloud-olingo-identity-ochat/persistence.xml at master · SAP/cloud-olingo-identity-ochat · GitHub  — it is configured to use your HCP Trial HANA instance as the data store. You should be able to copy over the <provider> tag and update the <properties> section (including the selection of “create-tables”).


      Let me know if that addresses the issue.


      Riley

      (0) 
  4. Vijay Singh Rajput

    Hi Riley,

    Need your help in same topic. I am trying same stuff using Apache Olingo version 2.0.6.

    I am following same setup as mention in Olingo documentation Apache Olingo Library

    But i am always getting null in following statement when calling from getQuery method.

    even i am tring with !deltatoken=1464260329818 query paramter in OData service call. may be i am missing some step. Kindly guide me.


    String deltaToken = ODataJPATombstoneContext.getDeltaToken();

    I am doing following steps:

    1. Extend Class ODataJPATombstoneEntityListener and override following method

    generateDeltaToken and getQuery

    2. Add Annotation @EntityListeners(xxx.JobTombstoneListener.class) in my Entity Class

    All the functionality is working fine if i remove @EntityListeners means without Delta token functionality.

    Thanks in advance.

    Best Regards,

    Vijay

    (0) 
    1. Riley Rainey Post author

      Hi Vijay,

      I’m unclear on the code your are starting from. The implementor has the flexibility to decide the appropriate format of a delta token.  Error handling as well.

      In my case, I chose to use an ISO-style date — mostly for clarity — it appears you are using code from another project — based on the format of the delta token, at least.  I’d suggest consulting my sample project to see how I generate and parse delta tokens:  sap_mobile_platform_espm_olingo_services/ESPMJPADeltaListener.java at master · SAP/sap_mobile_platform_espm_olingo_servi…

      (0) 

Leave a Reply