Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
former_member182638
Active Contributor
25,154

In my last blog series  (Build your first Mobile web app using jQuery Mobile and ABAP - Part 1) I introduced a simple approach to building your own a mobile web application quickly and easily using the open source framework jQuery Mobile  (http://www.jquerymobile.com) (currently in Alpha release), coupled with Business Server Pages in a SAP ABAP server. 

In this series I will illustrate a more advanced architectural approach, extending it with the following features:

  • Decoupling the web application from the data feed (rather than binding the entire application in a BSP framework)
  • Implementing a lean RESTful service for the data feed
  • Applying HTML5 / CSS3 concepts to enhance the web application, including CSS3 rendering, canvas, offline storage, and application caching
  • Finally extending the solution with PhoneGap  (http://www.phonegap.com) to access native capabilities of the device (eg. accelerometer, sounds, vibration)

To illustrate the above concepts I have constructed a simple scenario on a local miniSAP ABAP system.  The scenario I have chosen is actually incidental to the architecture and techniques used, but helps to demonstrate them nicely.  In the scenario, I have constructed a small 'instant value' web app that monitors the SAP system CPU and Memory metrics.

Let's have a look at the final application in this YouTube clip ....

Alternatively if you cannot view the YouTube clip, a Flash file version is available here ... http://www.johnmoy.com/scn/resources/sapsysmon.swf

Want to see this on your iPhone or Android device?  The following link launches a hosted version of the web app (note that this version will NOT be able to connect to your SAP system, due to cross-site scripting restrictions).

http://www.johnmoy.com/demos/zsystemmetrics/index.htm

(NOTE: this link will NOT render properly in Internet Explorer 6, 7 or 😎

Don't have an iPhone or Android device?  No worries.  If you have a recent version of Chrome or Safari installed on your desktop, then you can launch the web app from the following link ... (once again, this version will NOT be able to connect to your SAP system due to cross-site scripting restrictions).

http://testiphone.com/?url=http://www.johnmoy.com/demos/zsystemmetrics/index.htm

(NOTE: this link will NOT render properly in Internet Explorer 6, 7 or 😎

BUILD ME!!!

Interested in building this version yourself that will connect to your SAP system?  You can do this in your lunch break.  Just follow these steps in your own ABAP system ...

PRE-REQUISITES:

  • It is assumed you have development access to a ABAP WAS server.
  • It is assumed you know how to create ABAP classes and HTTP handlers in SICF
  • It is assumed for your instance, SAPOSCOL (operating system metrics collector) is running.  If you are running a miniSAP system, it may not be.  To check, execute function module 'FILL_SNAPSHOT_DATA' - if an error is returned, it is likely that SAPOSCOL is not running.  On my miniSAP system, I was able to start SAPOSCOL manually via a command prompt as follows ...

                        D:\SAP\NSP\SYS\exe\run\saposcol -l

  • To see all possible SAPOSCOL commands, type 'saposcol ?' at the command prompt

PART A: Enable basic RESTful service

  • Via transaction SE24, create a public class ZCL_OPERATING_SYSTEM_METRICS
  • Assign interface IF_HTTP_EXTENSION to this class.  This should introduce an instance method 'HANDLE_REQUEST' to our class.
  • For our implementation of HANDLE_REQUEST, paste the following code* ...

method if_http_extension~handle_request.
* This code has been simplified for illustrative purposes only.
* For productive use, you should seek to implement a RESTful framework,
* implement a JSON converter, and refactor to achieve appropriate
* separation of concerns.


*
* Data definition
*
  data:
    path_info     type string,
    verb          type string,
    json_string   type string.


*
* Process request
*
  path_info = server->request->get_header_field( name = '~path_info' ).
  verb = server->request->get_header_field( name = '~request_method' ).


*
* Determine if method is get.
*
  if verb ne 'GET'.
    call method server->response->set_header_field( name = 'Allow' value = 'GET' ).
    call method server->response->set_status( code = '405' reason = 'Method not allowed' ).
    exit.
  endif.


* Application logic.
* (in reality this would be refactored into a separate class)
  data: lv_lastupdate type char25,
        lt_cpu_all type table of cpu_all,
        ls_cpu_all type cpu_all,
        lt_mem_all type table of mem_all,
        ls_mem_all type mem_all.


* Firstly retrieve the system metrics
  call function 'FILL_SNAPSHOT_DATA'
    importing
      lastcollwrt = lv_lastupdate
    tables
      tf_cpu_all  = lt_cpu_all
      tf_mem_all  = lt_mem_all
    exceptions
      error       = 9.


* If error detected then abort
  if sy-subrc ne 0.
    call method server->response->set_status( code = '404' reason = 'ERROR' ).
    call method server->response->set_cdata( data = json_string ).
    exit.
  endif.


* Secondly extract the system metrics data
  read table lt_cpu_all index 1 into ls_cpu_all.
  read table lt_mem_all index 1 into ls_mem_all.


* Now populate JSON string with the appropriate fields we need
* (in reality it would be appropriate to implement and call a JSON converter)
  data: cpu_used type int4,
        cpu_used_string type string,
        mem_free_string type string,
        mem_used_string type string,
        mem_used type int4.
  cpu_used = ls_cpu_all-usr_total + ls_cpu_all-sys_total.
  move cpu_used to cpu_used_string.


  mem_used = ls_mem_all-phys_mem - ls_mem_all-free_mem.
  move mem_used to mem_used_string.

  move ls_mem_all-free_mem   to mem_free_string.


  concatenate '{ "sysmetric": { '
              '"updated": "' lv_lastupdate(24) '",  '
              '"cpu_used": ' cpu_used_string ',  '
              '"mem_free": ' mem_free_string ',  '
              '"mem_used": ' mem_used_string ' '
              '} }'
         into json_string.


*
* Set the content type
*
  call method server->response->set_header_field(
    name = 'Content-Type'
    value = 'application/json; charset=utf-8' ).


*
* Return the operating system metrics in a JSON string
*
  call method server->response->set_cdata( data = json_string ).


endmethod.

Note: I should mention that I cannibalised some code from this blog  (Android and RESTFul web service instead of SOAP) by Michael Hardenbol to develop this service.  You would probably want to implement a proper RESTful framework in your ICF if you intend to deploy a number of services (or wait for SAP's Gateway product).  SAP Mentor DJ Adams provides some ideas to accomplish this in his blog  (A new REST handler / dispatcher for the ICF).  Also, the code returns a result in JSON  (http://en.wikipedia.org/wiki/JSON) format.  Typically you would call a re-usable JSON converter (there are several available in the SCN community) but for the purposes of this exercise I have simply constructed the result with a crude CONCATENATE statement.

  • Via transaction SICF, create a new service 'zsystemmetrics' under the path /default_host/sap
  • For the service, add a description, then go to the 'Handler List' tab and add the following class into the handler list .... ZCL_OPERATING_SYSTEM_METRICS

  • Activate the service (from the SICF tree, right-click on the service and select 'Activate Service')

PART B: Enable Web Application

  • In this part we will use BSP simply as a 'container' for our web application.  You could just as readily host your application files in the MIMES directory.
  • Via transaction SE80, create a new BSP application ZSYSTEMMETRICS.
  • Right click on the BSP application ZSYSTEMMETRICS, and select CREATE -> PAGE.
  • Type 'index.htm' for the Page name, and a description, and select the Page Type 'Page with Flow Logic'.
  • For the Layout of the Page, open the following weblink  (http://www.johnmoy.com/demos/zsystemmetrics/index.htm) which launches the HTML hosted on my website, and view the source code with your browser.  Copy all the source into your BSP page layout.  NOTE: I was unable to provide the code in a textarea directly here because the editor was corrupting the HTML.  I will explain portions of this HTML/javascript later in this blog.  You may notice that there is in-line javascript and css in this file.  Typically it is best practice to separate these into external files, however for simplicity of this exercise I have collapsed them all into the same file.
  • Download the following image file to your desktop and save it with the name 'icon.png' ...

  • Right click on the BSP application and select CREATE -> MIME Object -> Import and select the image file (above) that you saved to your desktop.  Ensure that it is named 'icon.png'.
  • On your desktop, create a new text file named ''cache.manifest" and include the following text ...

CACHE MANIFEST
# Cache Manifest File for HTML5 application caching
# Amend the version below when any resource is updated
#
# Version 1.0
index.htm
icon.png
http://code.jquery.com/mobile/1.0a2/jquery.mobile-1.0a2.min.css
http://code.jquery.com/jquery-1.4.4.min.js
http://code.jquery.com/mobile/1.0a2/jquery.mobile-1.0a2.min.js
http://code.jquery.com/mobile/1.0a2/images/icons-18-white.png
NETWORK:
/sap/zsystemmetrics

  • Right click on the BSP application and select CREATE -> MIME Object -> Import and select the cache manifest file that you created on your desktop.  Set the filename to 'cache.manifest' and set the Mime Type to 'text/cache-manifest'.

Your application should look like this ...

  • Activate your BSP application.

TEST ME!!!

Now for the fun part ...

If you are launching this on a iPhone or Android device, launch the BSP application with the following URL ...

http://<FQDN>:<port>/sap/bc/bsp/sap/zsystemmetrics/index.htm

... where FQDN = fully qualified domain name

If you only have your desktop browser available (once again preferably Chrome or Safari) you can use the following website to 'visualise' your app in an iPhone ...

http://testiphone.com/?url=http://<FQDN>:<port>/sap/bc/bsp/sap/zsystemmetrics/index.htm

Using the latter approach, you should see something like this ...

Prefer to visualise this in an iPad?  Try the website www.ipadpeek.com, and you will see something like this ...

Now you can try out the app!  Be sure to specify the appropriate parameters in Settings -> Connection, so that your app can connect to the RESTful service.  Also choose your desired polling interval (in seconds) under Settings -> Polling.  Then navigate to Operating System Metrics, and press the Start button to commence monitoring.

OK, TELL ME HOW THIS WORKS?

Lets consider the architectural techniques used here and why they are beneficial to a mobile web app ...

1.  Decoupling the web application from the data feed

This separation gives us much more architectural flexibility.  The data feed could be much more readily positioned for re-use, feeding not just the Web app, but also a Native app or a Flex app for instance.  Also the web application built as a stand-alone web page better positions it to be cached on the device, and later we will see that it sets us up nicely for conversion into a Native (hybrid) app using PhoneGap.


2.  Implementing a lean RESTful approach to the data feed

RESTful services are gaining prominence in the world of mobile applications.  I noticed that SAP Mentor DJ Adams was blogging about the benefits of this architectural style way back in 2004 (talk about thought leadership!).  See this blog for a brief overview and links to other articles.  If you are not already aware, SAP's Gateway product is intended to provide RESTful service enablement for SAP backend systems.  However, it is possible already to code scenarios directly in ICF HTTP handlers.  This is what I have done here, albeit in a primitive manner (without development of a proper framework to enable multiple services).

In the specific example here the web application places a GET request for a 'system metrics' resource.  Note that we also choose to return the data in JSON format.

When the web app polls the RESTful service, it sends a GET request for the following URI ...

http://<FQDN>:<port>/sap/zsystemmetrics

... and receives a JSON formatted response like the following ...

{ "sysmetric": {"updated": "Sun Jan 16 22:18:09 2011","cpu_used":0 ,"mem_free":576172 ,"mem_used":1512000 } }

Note that this response is VERY lightweight.  This information is then used to draw the graphics for CPU and Memory usage.



3.  Applying HTML5 / CSS3 concepts to enhance the web application, including CSS3 rendering, canvas, offline storage, and application caching


Item A: Rounded corners

In the past, to achieve rounded corners you needed to provide an image file to achieve this effect for each corner.  Downloading image files consumes network bandwidth, and detracts from the user experience because of the added delay over slow mobile connections.  Now to achieve this rounding, you simply require a CSS declaration similar to the example below ...

        /* for rounded corners */
        -webkit-border-radius: 30px;
        -moz-border-radius: 30px;
        border-radius: 30px;

Item B: Reflection in text

This is a professional effect that is now easily achieved such as in the following example ...

      #titlereflect {
        color: #ecf1ef;
        -webkit-box-reflect: below -7px
        -webkit-gradient(linear, left top, left bottom, from(transparent), to(rgba(100, 100, 100, 0.2)));

Item C: Animated Gradient

This is an effect that you might see in Flash.  It is achieved here by declaring a gradient in CSS and simply shifting the position of this gradient over time.

See javascript function 'animateTitleLine()' in the supplied source code.

Item 😧 Menu

This function is provided by the jQuery Mobile framework.  Refer my earlier blog series or the jQuery Mobile documentation for how this is achieved.

Item E: CPU Usage graphic

This 'image' is actually drawn with the HTML5 'canvas' element.  In the past you would download the graphic from the server, but this would consume bandwidth and slow down response times.  Here we simply consume the lightweight JSON feed and draw the graphic dynamically in the browser with some javascript.

See javascript function 'plotBarChartData' in the supplied source code

Item F: Memory Usage graphic

Similar to E above.

See javascript function 'plotPieChartData' in the supplied source code

Item G: Placeholder text

HTML5 enables you to specify placeholder text in input fields.  The placeholder text appears until you start typing in the field.  Declaring this type of text is as simple as the following example ...

<input type="text" id="port" name="port" value="" placeholder="Please specify">

Item H: Sliders

These great controls are provided by jQuery Mobile.  See the jQuery Mobile documentation to see how these are declared.  An example is below ...

        <select name="sounds" id="sounds" data-role="slider">
          <option value="off">Off</option>
          <option value="on">On</option>
        </select>

Item I: Alerts

Instead of using standard javascript alerts, I leverage the ability for jQuery Mobile to transition to new pages using a 'pop' transition.

RESTful Service Call

The call to the SAP RESTful service is achieved using a jQuery AJAX call.  Here is the most important part (see the supplied source code for the full text) ...

      // Construct URL string
      var urlString = "http://" +
                      $('#server').val() + ":" +
                      $('#port').val() +
                      "/sap/zsystemmetrics";
      // Trigger AJAX call to ABAP server
      $.ajax({
         type: "GET",
         url: urlString,
         data: "",
         dataType: "json",
         beforeSend: function(xhr) {
           xhr.setRequestHeader('sap-user', $('#username').val());
           xhr.setRequestHeader('sap-password', $('#password').val());
           xhr.setRequestHeader('sap-client', $('#client').val());
         },
         success: function(sys){

                .... etc. process result here

Note that this http call encodes the sap username, password and client in the http request header.  Given that the data supplied by the RESTful service is not sensitive, this should be adequate (although you may wish to encrypt using https).  A discussion of security options is beyond the scope of this blog.

Offline Storage

This web application takes advantage of the HTML5 ability to store data on the client.  For this web application, all Settings parameters and the last system metrics received are saved to the client.  When the web application is launched, any stored values are interrogated and loaded into the app.  Storing data using HTML5 is easy.  For instance, to store your server name requires the following javascript code ...

localStorage.setItem("server", $('#server').val());

And retrieving the server name (when the web app is next launched) simply requires this code ...

$('#server').val(localStorage.getItem("server"));

Application Caching

HTML5 enables us to cache our web application on our browser indefinitely.  The benefit for us in our case is that if we declare the web app HTML and the jQuery Mobile resources to be cached, they will be cached by the browser and will not need to be downloaded every time the web app is accessed.  In effect the web app is now stored on the device.  This can dramatically improve start-up performance.

The key element here is the cache manifest file declared at the top of the HTML ...

<html manifest="cache.manifest">

This refers to a file (here named 'cache.manifest') which lists the resources to be cached (see earlier in the blog for the contents of this file).

This blog by John Carpinelli explains the concept well, and I have him to thank for outlining how to implement this in a BSP application.

Important: If you make changes to your web app, you need to upload a new (amended) version of your cache-manifest file (I generally adjust the comments and increment the version number).  Your web app will only reload amended resources if the cache-manifest file has been altered.

Other Comments

Certainly this web app does not utilise all concepts introduced by HTML5, but gives you a taste of what is possible.

If you are interested in learning more about HTML5 concepts, I would highly recommend the O'Reilly text 'HTML5 Up and Running'.

This video presentation also gives an excellent overview of HTML5 concepts.

4.  Finally extend the solution with PhoneGap to access native capabilities of the device (eg. accelerometer, sounds, vibration)

PhoneGap is an open source development framework that allows you to convert your web application into a 'native' (hybrid) application.  The framework provides a wrapper into which you insert your web app HTML and resources.  Wrappers are provided for different SDKs, including iPhone/iPad, Android, Palm, Symbian and Blackberry.  Importantly, the framework exposes access to native device features via a javascript API.  This means that via javascript your app can access native device features such as accelerometer, camera, compass, contacts, geolocation, vibration etc.  I will discuss this framework in Part 2 of this series, and walk you through the process of converting our web app into a native iPhone app.


43 Comments
Labels in this area