Skip to Content

Here it is the step-by-step explanation.

I’ll cut this elephant up into the following bite-sized chunks:

  1. The ‘before-you-start’ part
  2. The HTML5 part
  3. The SAPUI5 part
  4. The SICF part
  5. The ABAP part
  6. The Finished Product

1. The ‘before-you-start’ part

I have installed the windows version of Apache Web Server at the default location. This means I store all my web documents in the C:\Program Files (x86)\Apache Software Foundation\Apache2.2\htdocs folder in windows.

That folder for me is a bit of a mess right now, but that just means I probably understand enough about JavaScript to know that changing the file locations will break most of my demos. – I have no time just now for that complication …

I also have developer access to a ‘bog-standard’ SAP NetWeaver system. Which means I am registered as a developer there and can create ABAP code. You too need this.

In each section below I try to explain what is needed (The What) and then how to do it (The How).

2. The HTML5 part

The What

A Standalone Version

The following version will run independently of an SAP NetWeaver connection, I like to develop this way so that I can debug as I go along and don’t trip over myself at the very end. It’s your call.

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN” “http://www.w3.org/TR/html4/loose.dtd“>

<html>

                        <head>

                        <meta http-equiv=”content-type” content=”text/html;charset=utf-8″>

                        <title>d3.js gauges</title>

                                                <style>

                                                                        body

                                                                        {

                                                                                                font: 10px arial;

                                                                        }

                                                </style>

                                               

                                                <script type=”text/javascript” src=”d3.v3.min.js”></script>

                                                <script type=”text/javascript” src=”gauge.js”></script>

                                                <script>

                                                                                                                                               

                                                                                               

                                                                        var gauges = [];

                                                                       

                                                                        function createGauge(name, label, min, max)

                                                                        {

                                                                                                var config =

                                                                                                {

                                                                                                                        size: 120,

                                                                                                                        label: label,

                                                                                                                        min: undefined != min ? min : 0,

                                                                                                                        max: undefined != max ? max : 100,

                                                                                                                        minorTicks: 5

                                                                                                }

                                                                                               

                                                                                                var range = config.max – config.min;

                                                                                                config.yellowZones = [{ from: config.min + range*0.75, to: config.min + range*0.9 }];

                                                                                                config.redZones = [{ from: config.min + range*0.9, to: config.max }];

                                                                                               

                                                                                                gauges[name] = new Gauge(name + “GaugeContainer”, config);

                                                                                                gauges[name].render();

                                                                        }

                                                                       

                                                                        function createGauges()

                                                                        {

                                                                                                createGauge(“memory”, “Memory”);

                                                                                                createGauge(“cpu”, “CPU”);

                                                                                                createGauge(“network”, “Network”);

                                                                                                //createGauge(“test”, “Test”, -50, 50 );

                                                                        }

                                                                       

                                                                        function updateGauges()

                                                                        {

                                                                                                for (var key in gauges)

                                                                                                {

                                                                                                                        var value = getRandomValue(gauges[key])

                                                                                                                        gauges[key].redraw(value);

                                                                                                }

                                                                        }

                                                                       

                                                                        function getRandomValue(gauge)

                                                                        {

                                                                                                var overflow = 0; //10;

                                                                                                return gauge.config.min – overflow + (gauge.config.max – gauge.config.min + overflow*2) *  Math.random();

                                                                        }

                                                                       

                                                                        function initialize()

                                                                        {

                                                                                                createGauges();

                                                                                                setInterval(updateGauges, 1000);

                                                                        }

                                                                       

                                                </script>

                                               

                        </head>

                       

<body onload=”initialize()”>

                        <span id=”memoryGaugeContainer”></span>

                        <span id=”cpuGaugeContainer”></span>

                        <span id=”networkGaugeContainer”></span>

                        <span id=”testGaugeContainer”></span>

</body>

                       

</html>

The Final Version

\SAPPerfVis\SAPGauges.html:

     

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN” “http://www.w3.org/TR/html4/loose.dtd“>

<html>

                        <head>

                        <meta http-equiv=”content-type” content=”text/html;charset=utf-8″>

                        <title>SAP Gauges</title>

                                               

                                                <style>

                                                                        body

                                                                        {

                                                                                                font: 10px arial;

                                                                        }

                                                </style>

                                               

                                                <script type=”text/javascript” src=”d3.v3.min.js”></script>

                                                <script type=”text/javascript” src=”gauge.js”></script>

                                                <script>

                                                                        // initialize variables

                                                                        var gauges = [];

                                                                        var timestamp;

                                                                        var free_mem_pc;

                                                                        var cpu_idle;

                                                                        var lan_packets;

                                               

                                                                        function createGauge(name, label, min, max)

                                                                        // set up the parameters and call the generic function stored in gauge.js

                                                                        {

                                                                                                var config =

                                                                                                {

                                                                                                                        size: 120,

                                                                                                                        label: label,

                                                                                                                        min: undefined != min ? min : 0,

                                                                                                                        max: undefined != max ? max : 100,

                                                                                                                        minorTicks: 5

                                                                                                }

                                                                                               

                                                                                                var range = config.max – config.min;

                                                                                                config.yellowZones = [{ from: config.min + range*0.75, to: config.min + range*0.9 }];

                                                                                                config.redZones = [{ from: config.min + range*0.9, to: config.max }];

                                                                                               

                                                                                                gauges[name] = new Gauge(name + “GaugeContainer”, config);

                                                                                                gauges[name].render();

                                                                        }

                                                                       

                                                                        function createGauges()

                                                                        // just ……. do it, already

                                                                        {

                                                                                                createGauge(“memory”, “Memory”);

                                                                                                createGauge(“cpu”, “CPU”);

                                                                                                createGauge(“network”, “Network”);

                                                                        }

                                                                        function getData ()

                                                                        // fetch the data from the NetWeaver server

                                                                        {

                                                                                                d3.text(http://<your_host>:<your_port>/sap/zdemo_icf_001“, function(error, result) {

                                                                                                                        obj = JSON.parse(result);

                                                                                                                        timestamp = obj.Timestamp;

                                                                                                                        free_mem_pc = obj.free_mem_pc;

                                                                                                                        cpu_idle = obj.idle_total;

                                                                                                                        lan_packets = obj.packets;

                                                                                                                        if (error) return console.warn(error);

                                                                                                                        updateGauges();

//                                                                                                                     if (result) return console.log(result);

                                                                                                });

                                                                        }

                                                                       

                                                                        function updateGauges()

                                                                        // redraw the Gauges with the latest data from the NetWeaver server

                                                                        {                      

                                                                                                                        gauges[“memory”].redraw(100 – parseInt(free_mem_pc));

                                                                                                                        gauges[“cpu”].redraw(100 – parseInt(cpu_idle));

                                                                                                                        gauges[“network”].redraw(lan_packets);

                                                                                                                        d3.select (“#refreshtimestamp”)

                                                                                                                                                .text(“last refreshed ” + timestamp);

                                                                        }

                                                                       

                                                                        function initialize()

                                                                        //initialise the gauges and set the ‘ping’ interval

                                                                        {

                                                                                                createGauges();

                                                                                                getData();

                                                                                                setInterval(getData, 5000);

                                                                        }

                                                                       

                                                </script>

                                               

                        </head>

                       

<body onload=”initialize()”>

<span id=”memoryGaugeContainer”></span>

                        <span id=”cpuGaugeContainer”></span>

                        <span id=”networkGaugeContainer”></span>

<footer style=”text-align: center;”>

                        <p style=”color: #eee; width:300px; font-size:13px;”>

                                                <span id=”system”>BI Lab – </span>

                                                <span id=”refreshtimestamp”>last refreshed at:</span>

                        </p>

</footer>         

</body>           

</html>

                     

\SAPPerfVis\gauge.js (huge kudos to Tomer Doron for this excellent D3 example):

     

function Gauge(placeholderName, configuration)

{

                        this.placeholderName = placeholderName;

                       

                        var self = this; // for internal d3 functions

                       

                        this.configure = function(configuration)

                        {

                                                this.config = configuration;

                                               

                                                this.config.size = this.config.size * 0.9;

                                               

                                                this.config.raduis = this.config.size * 0.97 / 2;

                                                this.config.cx = this.config.size / 2;

                                                this.config.cy = this.config.size / 2;

                                               

                                                this.config.min = undefined != configuration.min ? configuration.min : 0;

                                                this.config.max = undefined != configuration.max ? configuration.max : 100;

                                                this.config.range = this.config.max – this.config.min;

                                               

                                                this.config.majorTicks = configuration.majorTicks || 5;

                                                this.config.minorTicks = configuration.minorTicks || 2;

                                               

                                                this.config.greenColor = configuration.greenColor || “#109618”;

                                                this.config.yellowColor = configuration.yellowColor || “#FF9900”;

                                                this.config.redColor = configuration.redColor || “#DC3912”;

                                               

                                                this.config.transitionDuration = configuration.transitionDuration || 500;

                        }

                        this.render = function()

                        {

                                                this.body = d3.select(“#” + this.placeholderName)

                                                                                                                                                                        .append(“svg:svg”)

                                                                                                                                                                        .attr(“class”, “gauge”)

                                                                                                                                                                        .attr(“width”, this.config.size)

                                                                                                                                                                        .attr(“height”, this.config.size);

                                               

                                                this.body.append(“svg:circle”)

                                                                                                                        .attr(“cx”, this.config.cx)

                                                                                                                        .attr(“cy”, this.config.cy)

                                                                                                                        .attr(“r”, this.config.raduis)

                                                                                                                        .style(“fill”, “#ccc”)

                                                                                                                        .style(“stroke”, “#000”)

                                                                                                                        .style(“stroke-width”, “0.5px”);

                                                                                                                       

                                                this.body.append(“svg:circle”)

                                                                                                                        .attr(“cx”, this.config.cx)

                                                                                                                        .attr(“cy”, this.config.cy)

                                                                                                                        .attr(“r”, 0.9 * this.config.raduis)

                                                                                                                        .style(“fill”, “#fff”)

                                                                                                                        .style(“stroke”, “#e0e0e0”)

                                                                                                                        .style(“stroke-width”, “2px”);

                                                                                                                       

                                                for (var index in this.config.greenZones)

                                                {

                                                                        this.drawBand(this.config.greenZones[index].from, this.config.greenZones[index].to, self.config.greenColor);

                                                }

                                               

                                                for (var index in this.config.yellowZones)

                                                {

                                                                        this.drawBand(this.config.yellowZones[index].from, this.config.yellowZones[index].to, self.config.yellowColor);

                                                }

                                               

                                                for (var index in this.config.redZones)

                                                {

                                                                        this.drawBand(this.config.redZones[index].from, this.config.redZones[index].to, self.config.redColor);

                                                }

                                               

                                                if (undefined != this.config.label)

                                                {

                                                                        var fontSize = Math.round(this.config.size / 9);

                                                                        this.body.append(“svg:text”)

                                                                                                                                                .attr(“x”, this.config.cx)

                                                                                                                                                .attr(“y”, this.config.cy / 2 + fontSize / 2)

                                                                                                                                                .attr(“dy”, fontSize / 2)

                                                                                                                                                .attr(“text-anchor”, “middle”)

                                                                                                                                                .text(this.config.label)

                                                                                                                                                .style(“font-size”, fontSize + “px”)

                                                                                                                                                .style(“fill”, “#333”)

                                                                                                                                                .style(“stroke-width”, “0px”);

                                                }

                                               

                                                var fontSize = Math.round(this.config.size / 16);

                                                var majorDelta = this.config.range / (this.config.majorTicks – 1);

                                                for (var major = this.config.min; major <= this.config.max; major += majorDelta)

                                                {

                                                                        var minorDelta = majorDelta / this.config.minorTicks;

                                                                        for (var minor = major + minorDelta; minor < Math.min(major + majorDelta, this.config.max); minor += minorDelta)

                                                                        {

                                                                                                var point1 = this.valueToPoint(minor, 0.75);

                                                                                                var point2 = this.valueToPoint(minor, 0.85);

                                                                                               

                                                                                                this.body.append(“svg:line”)

                                                                                                                                                                        .attr(“x1”, point1.x)

                                                                                                                                                                        .attr(“y1”, point1.y)

                                                                                                                                                                        .attr(“x2”, point2.x)

                                                                                                                                                                        .attr(“y2”, point2.y)

                                                                                                                                                                        .style(“stroke”, “#666”)

                                                                                                                                                                        .style(“stroke-width”, “1px”);

                                                                        }

                                                                       

                                                                        var point1 = this.valueToPoint(major, 0.7);

                                                                        var point2 = this.valueToPoint(major, 0.85);       

                                                                       

                                                                        this.body.append(“svg:line”)

                                                                                                                                                .attr(“x1”, point1.x)

                                                                                                                                                .attr(“y1”, point1.y)

                                                                                                                                                .attr(“x2”, point2.x)

                                                                                                                                                .attr(“y2”, point2.y)

                                                                                                                                                .style(“stroke”, “#333”)

                                                                                                                                                .style(“stroke-width”, “2px”);

                                                                       

                                                                        if (major == this.config.min || major == this.config.max)

                                                                        {

                                                                                                var point = this.valueToPoint(major, 0.63);

                                                                                               

                                                                                                this.body.append(“svg:text”)

                                                                                                                                                                        .attr(“x”, point.x)

                                                                                                                                                                        .attr(“y”, point.y)

                                                                                                                                                                        .attr(“dy”, fontSize / 3)

                                                                                                                                                                        .attr(“text-anchor”, major == this.config.min ? “start” : “end”)

                                                                                                                                                                        .text(major)

                                                                                                                                                                        .style(“font-size”, fontSize + “px”)

                                                                                                                                                                        .style(“fill”, “#333”)

                                                                                                                                                                        .style(“stroke-width”, “0px”);

                                                                        }

                                                }

                                               

                                                var pointerContainer = this.body.append(“svg:g”).attr(“class”, “pointerContainer”);

                                               

                                                var midValue = (this.config.min + this.config.max) / 2;

                                               

                                                var pointerPath = this.buildPointerPath(midValue);

                                               

                                                var pointerLine = d3.svg.line()

                                                                                                                                                                                                                        .x(function(d) { return d.x })

                                                                                                                                                                                                                        .y(function(d) { return d.y })

                                                                                                                                                                                                                        .interpolate(“basis”);

                                               

                                                pointerContainer.selectAll(“path”)

                                                                                                                                                                        .data([pointerPath])

                                                                                                                                                                        .enter()

                                                                                                                                                                                                .append(“svg:path”)

                                                                                                                                                                                                                        .attr(“d”, pointerLine)

                                                                                                                                                                                                                        .style(“fill”, “#dc3912”)

                                                                                                                                                                                                                        .style(“stroke”, “#c63310”)

                                                                                                                                                                                                                        .style(“fill-opacity”, 0.7)

                                                                                                                       

                                                pointerContainer.append(“svg:circle”)

                                                                                                                                                                        .attr(“cx”, this.config.cx)

                                                                                                                                                                        .attr(“cy”, this.config.cy)

                                                                                                                                                                        .attr(“r”, 0.12 * this.config.raduis)

                                                                                                                                                                        .style(“fill”, “#4684EE”)

                                                                                                                                                                        .style(“stroke”, “#666”)

                                                                                                                                                                        .style(“opacity”, 1);

                                               

                                                var fontSize = Math.round(this.config.size / 10);

                                                pointerContainer.selectAll(“text”)

                                                                                                                                                                        .data([midValue])

                                                                                                                                                                        .enter()

                                                                                                                                                                                                .append(“svg:text”)

                                                                                                                                                                                                                        .attr(“x”, this.config.cx)

                                                                                                                                                                                                                        .attr(“y”, this.config.size – this.config.cy / 4 – fontSize)

                                                                                                                                                                                                                        .attr(“dy”, fontSize / 2)

                                                                                                                                                                                                                        .attr(“text-anchor”, “middle”)

                                                                                                                                                                                                                        .style(“font-size”, fontSize + “px”)

                                                                                                                                                                                                                        .style(“fill”, “#000”)

                                                                                                                                                                                                                        .style(“stroke-width”, “0px”);

                                               

                                                this.redraw(this.config.min, 0);

                        }

                       

                        this.buildPointerPath = function(value)

                        {

                                                var delta = this.config.range / 13;

                                               

                                                var head = valueToPoint(value, 0.85);

                                                var head1 = valueToPoint(value – delta, 0.12);

                                                var head2 = valueToPoint(value + delta, 0.12);

                                               

                                                var tailValue = value – (this.config.range * (1/(270/360)) / 2);

                                                var tail = valueToPoint(tailValue, 0.28);

                                                var tail1 = valueToPoint(tailValue – delta, 0.12);

                                                var tail2 = valueToPoint(tailValue + delta, 0.12);

                                               

                                                return [head, head1, tail2, tail, tail1, head2, head];

                                               

                                                function valueToPoint(value, factor)

                                                {

                                                                        var point = self.valueToPoint(value, factor);

                                                                        point.x -= self.config.cx;

                                                                        point.y -= self.config.cy;

                                                                        return point;

                                                }

                        }

                       

                        this.drawBand = function(start, end, color)

                        {

                                                if (0 >= end – start) return;

                                               

                                                this.body.append(“svg:path”)

                                                                                                                        .style(“fill”, color)

                                                                                                                        .attr(“d”, d3.svg.arc()

                                                                                                                                                .startAngle(this.valueToRadians(start))

                                                                                                                                                .endAngle(this.valueToRadians(end))

                                                                                                                                                .innerRadius(0.65 * this.config.raduis)

                                                                                                                                                .outerRadius(0.85 * this.config.raduis))

                                                                                                                        .attr(“transform”, function() { return “translate(” + self.config.cx + “, ” + self.config.cy + “) rotate(270)” });

                        }

                       

                        this.redraw = function(value, transitionDuration)

                        {

                                                var pointerContainer = this.body.select(“.pointerContainer”);

                                               

                                                pointerContainer.selectAll(“text”).text(Math.round(value));

                                               

                                                var pointer = pointerContainer.selectAll(“path”);

                                                pointer.transition()

                                                                                                                        .duration(undefined != transitionDuration ? transitionDuration : this.config.transitionDuration)

                                                                                                                        //.delay(0)

                                                                                                                        //.ease(“linear”)

                                                                                                                        //.attr(“transform”, function(d)

                                                                                                                        .attrTween(“transform”, function()

                                                                                                                        {

                                                                                                                                                var pointerValue = value;

                                                                                                                                                if (value > self.config.max) pointerValue = self.config.max + 0.02*self.config.range;

                                                                                                                                                else if (value < self.config.min) pointerValue = self.config.min – 0.02*self.config.range;

                                                                                                                                                var targetRotation = (self.valueToDegrees(pointerValue) – 90);

                                                                                                                                                var currentRotation = self._currentRotation || targetRotation;

                                                                                                                                                self._currentRotation = targetRotation;

                                                                                                                                               

                                                                                                                                                return function(step)

                                                                                                                                                {

                                                                                                                                                                        var rotation = currentRotation + (targetRotation-currentRotation)*step;

                                                                                                                                                                        return “translate(” + self.config.cx + “, ” + self.config.cy + “) rotate(” + rotation + “)”;

                                                                                                                                                }

                                                                                                                        });

                        }

                       

                        this.valueToDegrees = function(value)

                        {

                                                // thanks @closealert

                                                //return value / this.config.range * 270 – 45;

                                                return value / this.config.range * 270 – (this.config.min / this.config.range * 270 + 45);

                        }

                       

                        this.valueToRadians = function(value)

                        {

                                                return this.valueToDegrees(value) * Math.PI / 180;

                        }

                       

                        this.valueToPoint = function(value, factor)

                        {

                                                return {              x: this.config.cx – this.config.raduis * factor * Math.cos(this.valueToRadians(value)),

                                                                                                                        y: this.config.cy – this.config.raduis * factor * Math.sin(this.valueToRadians(value))                                                };

                        }

                       

                        // initialization

                        this.configure(configuration);     

}

                     

Layman’s Explanation

Essentially the above Final Version HTML builds an HTML document with a <body> section that contains 3 <span> elements, and a <footer>.

The page references the d3.v3.min.js library and the gauges.js script.

When the <body> initializes it calls the following functions, in order:

      • createGauges() – to build 3 instances of the gauge object (via gauge.js and d3.v3.min.js) and to locate them each at the appropriate <span> location;
      • getData() – to connect to the SICF service on the named server and retrieve the response; and
      • setInterval() – to refresh the data at the defined intervals and keep refreshing until we shut the page.

The How

You will need to copy and paste the Final Version into a new HTML document, using whatever IDE you like. I use Notepad++.

Save the document in the documents folder of your local web server. I created a subfolder called ‘\SAPPerfVis\’ and called my HTML file ‘SAPGauges.html’:

                C:\Program Files (x86)\Apache Software Foundation\Apache2.2\htdocs\SAPPerfVis\SAPGauges.html

NB! Also create the ‘gauges.js’ file to the same location (go here for a version), and don’t forget the ‘d3.v3.min.js’ file too (go here for a version)

Call your document from a browser session to test it. If you used the default folder and configured your web server appropriately you will find your file at the following location:

http://localhost:8888/SAPPerfVis/SAPGauges.html

NNB! I use Chrome during development and rely heavily on the Console and the debugging features which are also legendary, if a little fiddly.

At this stage the Final Version will not do anything as we haven’t yet built the SAP logic to receive the call, or to collect and send back the data. You could use the Standalone Version, that uses a random number generator to test your installation (and Ctrl+C, Ctrl-V and file naming skills 😛 ).

3. The SAPUI5 part

I downloaded the SAPUI5 package from here, unpacked it to my htdocs folder of my Apache webserver. I then explored the SAPUI5 demokit to find an interesting template to host the D3 magic. I settled on the Shell layout as it just looks so SAPUI5-ish. I thought it would also give me an opportunity to work with the new SAPUI5 elements and experiment a bit for myself.

But I am first-and-foremost an adapter of technology – as someone once quoted: ‘Life’s too short to know everything’. This means I typically take the good work of others and cut and paste to meet my own requirements.

In the case of the SAP Shell demo template I liked the colour scheme, I liked the bells and whistles and in particular I liked the menu function at the top of the page. So I made a copy of the SAPUI5 Shell document, and began to adapt it.

The What

Here is a description of the SAPUI5 Shell demo template and my adaptations:

<!DOCTYPE HTML>

<html>

                        <head>

                                                <meta http-equiv=”X-UA-Compatible” content=”IE=edge” />

                                                <meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″>

                                                <meta name=”keywords” content=”Control Shell” />

                                                <title>Shell Example – SAPUI5 Demo Kit</title>

                                                <link rel=”stylesheet” type=”text/css” href=”/demokit/theme/default.css” />

                                                <script id=”sap-ui-bootstrap”

                                                                                                type=”text/javascript”

                                                                                                src=”/demokit/resources/sap-ui-core.js”

                                                                                                data-sap-ui-theme=”sap_goldreflection”

                                                                                                data-sap-ui-libs=”sap.ui.commons,sap.ui.ux3,sap.ui.demokit”>

                                                </script>

                                                <script type=”text/javascript”>sap.ui.demokit._supportedThemes = [“sap_goldreflection”, “sap_hcb”];</script>

                                                <script type=”text/javascript” src=/demokit/js/utils.js”></script>

                                                <script type=”text/javascript”>

                                                                        var oCode = new sap.ui.demokit.CodeSampleContainer(“csc1”, {

                                                                                                                        scriptElementId : ‘Script1’,

                                                                                                                        uiAreaId : ‘dummy1’,

                                                                                                                        sourceVisible: false,

                                                                                                                        apply : function(e) {

                                                                                                                                                // remove old content from UIArea

                                                                                                                                                sap.ui.getCore().getUIArea(“sample1”).setRootControl(null);

                                                                                                                                                oShell.removeAllContent();

                                                                                                                                                oShell.destroy();

                                                                                                                                                eval(e.getParameters()[‘code’]);

                                                                                                                        }

                                                                                                });

                                                                        var oHTML = new sap.ui.core.HTML(“myContent”,{

                                                                                                content: ‘<div>’+

                                                                          ‘<div id=”sample1code” ></div>’+

                                                                                                ‘</div>’

                                                                        });

                                                                        oHTML.addDelegate({

                                                                                                onAfterRendering: function(){

                                                                                                                        sap.ui.getCore().byId(“Gauges”).placeAt(“sample1code”);

                                                                                                }

                                                                        });

                                                                        var oGauges = new sap.ui.core.HTML(“Gauges”,{

                                                                                                content: ‘<div>’+

                                                                                                ‘<iframe src=”SAPPerfVis/SAPGauges.html” width=”1000px” height=”600px” name=”Gauges” frameborder=”0″>’+

                                                                                                ‘</iframe>’+

                                                                                                ‘</div>’

                                                                        });

                                                </script>

<script id=’Script1′ type=”text/javascript”>

var oShell = new sap.ui.ux3.Shell(“myShell”, {

                        appTitle: “SAPUI5 Analytics Demo”,

                        appIcon: “”,

                        appIconTooltip: “Tooltip”,

                        showLogoutButton: true,

                        showSearchTool: true,

                        showInspectorTool: true,

                        showFeederTool: true,

                        worksetItems: [

                                                new sap.ui.ux3.NavigationItem(“WI_1″,{key:”wi_1″,text:”SAPUI5 Demo”, subItems:[

                                                new sap.ui.ux3.NavigationItem(“WI_1_1″,{key:”wi_1_1″,text:”Gauges”})

                                                ]}),

                                       ],

                        paneBarItems: [new sap.ui.core.Item(“PI_Date”,{key:”pi_date”,text:”date”}),

                                                new sap.ui.core.Item(“PI_Browser”,{key:”pi_browser”,text:”browser”})],

                                                content: oHTML,

                                                toolPopups: [new sap.ui.ux3.ToolPopup(“contactTool”,{

                                                                        title: “New Contact”,

                                                                        tooltip: “Create New Contact”,

                                                                        icon: “images/Contact_regular.png”,

                                                                        iconHover: “images/Contact_hover.png”,

                                                                        content:[new sap.ui.commons.TextView({text:”Here could be a contact sheet.”})],

                                                                        buttons: [new sap.ui.commons.Button(“cancelContactButton”, {text:”Cancel”,press:function(oEvent){

                                                                        sap.ui.getCore().byId(“contactTool”).close();

                                                                        }})]

                                                })],

                        headerItems: [new sap.ui.commons.TextView({text:”User Name”,tooltip:”U.Name”}),

                                      new sap.ui.commons.Button({text:”Personalize”,tooltip:”Personalize”,press:function(oEvent){alert(“Here could open an personalize dialog”);}}),

                                                new sap.ui.commons.MenuButton({

                                                                                                text: “Help”,

                                                                                                tooltip: “Help Menu”,

                                                                                                menu: new sap.ui.commons.Menu(“menu1”,{items:[                                                                                                                                                                

                                                new sap.ui.commons.MenuItem(“menuitem1″,{text:”Help”}),

                                                new sap.ui.commons.MenuItem(“menuitem2″,{text:”Report Incident”}),

                                                new sap.ui.commons.MenuItem(“menuitem3″,{text:”About”})]})

                                                })],

                       

worksetItemSelected: function(oEvent){

                                                var sId = oEvent.getParameter(“id”);

                                                var oShell = oEvent.oSource;

                                                switch (sId) {

                                                case “WI_2_home”:

                                                                        oShell.setContent(oHTML);

                                                                        break;

                                                case “WI_1_1”:

                                                                        oShell.setContent(oGauges);

                                                                        break;

                                                default:

                                                                        break;

                                                }

                        },

                        paneBarItemSelected: function(oEvent){

                                                var sKey = oEvent.getParameter(“key”);

                                                var oShell = oEvent.oSource;

                                                switch (sKey) {

                                                case “pi_date”:

                                                                        var oDate = new Date();

                                                                        oShell.setPaneContent(new sap.ui.commons.TextView({text:oDate.toLocaleString()}), true);

                                                                        break;

                                                case “pi_browser”:

                                                                        oShell.setPaneContent(new sap.ui.commons.TextView({text:”Your browser provides the following information:\n”+navigator.userAgent}), true);

                                                                        break;

                                                default:

                                                                        break;

                                                }

                        },

                        logout:function(){

                                                alert(“Logout Button has been clicked.\nThe application can now do whatever is required.”);

                        },

                        search:function(oEvent){

                                                alert(“Search triggered: ” + oEvent.getParameter(“text”));

                        },

                        feedSubmit:function(oEvent){

                                                alert(“Feed entry submitted: ” + oEvent.getParameter(“text”));

                        }

}).placeAt(“sample1”);

</script>

</head>

<body class=”sapUiBody” role=”application”>

                        <div id=”sample1″ ></div>

</body>

</html>

Layman’s Explanation

The SAPUI5 Shell template has the following components:

A reference to the SAPUI5 JavaScript librarys:

  1. /demokit/resources/sap-ui-core.js and
  2. /demokit/js/utils.js

Then the JavaScript initializes a few variables:

  1. oCode – this bit preps the later Script1 script and is part of the SAPUI5 framework
  2. oHTML – this is the inner HTML that is created by scripting logic
  3. oGauges – this is a new div and iframe that points to the SAPPerfVis/SAPGauges.html page

After that a further script builds the Shell template:

  • oShell is created with reference to the SAPUI5 sap.ui.ux3.Shell element
  • A few parameters are then initialised:
    • worksetitems – this is bit that controls the NavigationItems at the top of the page (see our “Gauges” reference

workSetItems.png

    • panelBarItems set to control the … Panel Bar

panelBarItems.png

    • then comes the content (= oHTML)
    • next comes the toolPopups:

toolPopups.png

    • the headerItems follow on:

headerItems.png

    • And finally the Help Menu and its menuItems

menuItems.png

  • The next section of code handles the selection of elements in the workset:
    • worksetItemSelected


  • There is a portion dealing with the panelBar selections:
    • paneBarItemSelected


  • The main logic concludes with handlers for the remaining selection events.

The How

Save this to the ‘\SAPPerfVis\’ folder as ‘ShellDemo.html’.

Make sure you have the DEMOKIT of the SAPUI5 libraries in the default location too (ie the root of your web server: htdocs). I have a folder there called ‘\demokit\’.

4. The SICF part

The What

You should already know this, if not go back my earlier post here.

The How

Logon to your SAP NetWeaver system and run transaction SICF.

This takes you to the Internet Connection Framework. Navigate to the following location and right-click to create a new service:

SICF.png

Create a Service:

Create Service.png

Add a technical name and description:

SICF Example.png

Add logon details, if you want to avoid having to log on:

Service Logon.PNG

5. The ABAP part

The What

I’ve added a description of the SAP ABAP logic below in the Layman’s Explanation section. I’m not an ABAPer by training, but we SAP BW guys get our fingers dirty in many areas so we often ‘rise above our stations’. Nevertheless <insert generic apology for standard of ABAP code here>.

The How

Create a new Handler Class

Service Handler.PNG

Go to the Handler Method:

Handler Builder.PNG

Insert the following code in the HANDLE_REQUEST method

     

METHOD if_http_extension~handle_request.

  DATA: name         TYPE string.

  DATA: l_tf_mem_all    TYPE TABLE OF mem_all,

         l_tf_cpu_all    TYPE TABLE OF cpu_all,

         l_tf_lan_single TYPE TABLE OF lan_single,

         s_mem_all       LIKE LINE OF l_tf_mem_all,

         s_cpu_all       LIKE LINE OF l_tf_cpu_all,

         s_lan_single    LIKE LINE OF l_tf_lan_single,

         l_free_mem      TYPE n LENGTH 8,

         l_phys_mem      TYPE n LENGTH 8,

         l_swap_free     TYPE n LENGTH 8,

         l_swap_max      TYPE n LENGTH 8,

         l_free_mem_pc   TYPE n LENGTH 8,

         l_swap_free_pc  TYPE n LENGTH 8,

         l_lastcollwrt   TYPE char25,

         l_idle_total    TYPE n LENGTH 8,

         l_packets       TYPE n LENGTH 8,

         json_string     TYPE string.

  CALL FUNCTION ‘FILL_SNAPSHOT_DATA’

*     EXPORTING

*       LOCAL_REMOTE                         = ‘LOCAL’

*       LOGICAL_DESTINATION                  =

*       SYSTEM_ID                            = 0

     IMPORTING

*       F_CPU_ALL_READ                       =

*       F_MEM_ALL_READ                       =

*       F_DISK_SINGLE_READ                   =

*       F_LAN_SINGLE_READ                    =

*       F_TOP_SINGLE_READ                    =

*       TAB_TYPE                             =

*       ACTIVEFLAG                           =

*       INTERVAL                             =

*       DETAILSCOLL                          =

*       DETAILSREQI                          =

*       DETAILSMODE                          =

       lastcollwrt                          = l_lastcollwrt

*       LASTCOLLINT                          =

*       NORMCOLLINT                          =

*       F_POOL_ALL_READ                      =

*       F_SPAG_ALL_READ                      =

*       F_STOR_ALL_READ                      =

*       F_CPU_SINGLE_READ                    =

*       F_POOL_SINGLE_READ                   =

*       F_CPU_VIRT_AIX_READ                  =

   TABLES

     tf_cpu_all                           = l_tf_cpu_all

     tf_mem_all                           = l_tf_mem_all

*       TF_DISK_SINGLE                       =

     tf_lan_single                        = l_tf_lan_single

*       TF_TOP_SINGLE                        =

*       TF_POOL_ALL                          =

*       TF_SPAG_ALL                          =

*       TF_STOR_ALL                          =

*       TF_CPU_SINGLE                        =

*       TF_POOL_SINGLE                       =

*       TF_CPU_VIRT_AIX                      =

*     EXCEPTIONS

*       INTERNAL_ERROR_ADRESS_FAILED         = 1

*       INTERNAL_ERROR_DIFFERENT_FIELD       = 2

*       INTERNAL_ERROR_NO_NEW_LINE           = 3

*       COLLECTOR_NOT_RUNNING                = 4

*       SHARED_MEMORY_NOT_AVAILABLE          = 5

*       COLLECTOR_BUSY                       = 6

*       VERSION_CONFLICT                     = 7

*       NO_NETWORK_COLLECTOR_RUNNING         = 8

*       SYSTEM_FAILURE                       = 9

*       COMMUNICATION_FAILURE                = 10

*       OTHERS                               = 11

            .

  IF sy-subrc <> 0.

*     MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO

*             WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.

  ENDIF.

*Get Timestamp

  CONCATENATE json_string

              ‘{“Timestamp”: “‘

              l_lastcollwrt(24)

              ‘”, ‘

    INTO json_string.

* Get Memory Data

  LOOP AT l_tf_mem_all INTO s_mem_all.

    l_free_mem = s_mem_all-free_mem.

    l_phys_mem = s_mem_all-phys_mem.

    l_swap_free = s_mem_all-swap_free.

    l_swap_max = s_mem_all-swap_max.

    l_free_mem_pc = l_free_mem  / l_phys_mem * 100.

    SHIFT l_free_mem_pc LEFT DELETING LEADING ‘0’.

    l_swap_free_pc = l_swap_free / l_swap_max * 100.

    SHIFT l_swap_free_pc LEFT DELETING LEADING ‘0’.

    CONCATENATE json_string

                ‘”free_mem_pc”: “‘

                l_free_mem_pc

                ‘”, ‘

        INTO json_string.

  ENDLOOP.

* Get CPU data

  LOOP AT l_tf_cpu_all INTO s_cpu_all.

    l_idle_total = s_cpu_all-idle_total.

    SHIFT l_idle_total LEFT DELETING LEADING ‘0’.

    CONCATENATE json_string

                ‘”idle_total”: “‘

                l_idle_total

                ‘”, ‘

        INTO json_string.

  ENDLOOP.

* Get Network data (currently only ‘lo’)

  LOOP AT l_tf_lan_single INTO s_lan_single

    WHERE lanname = ‘lo’.

    l_packets = s_lan_single-packets.

    SHIFT l_packets LEFT DELETING LEADING ‘0’.

    CONCATENATE json_string

                ‘”packets”: “‘

                l_packets

                ‘”}’

        INTO json_string.

  ENDLOOP.

* Enable this service to be available to other sites

*

  server->response->set_header_field( name = ‘Access-Control-Allow-Origin’ value = ‘*’ ).

*

* Return the results in a JSON string

*

  server->response->set_cdata( data = json_string ).

ENDMETHOD.

                     

Save, Check and then Activate your new Handler Class.

Layman’s Explanation

This is really not that challenging:

  • First off we initialize some variables;
  • Then we call the FILL_SNAPSHOT_DATA function module, returning
    • l_lastcollwrt
    • l_tf_cpu_all
    • l_tf_mem_all
    • l_tf_lan_single
  • Next we build up the JSON object that will be returned to the calling client
  • Finally there are 2 closing statements:
    • one to overcome the cross-domain call:

server->response->set_header_field( name = ‘Access-Control-Allow-Origin’ value = ‘*’ )

    • and lastly the call to return the response:

server->response->set_cdata( data = json_string )

6. The Finished Product

Ta-Da!

Watch the dials react every 5 seconds. You’ll also see the date and time change too.

Final Output_shrt.png

Please take the time to let me know how you found the series and where I should change things to aid deeper understanding.

It’s been an  exciting first week of blogging, all inspired by the good folks at the Mastering SAP Analytics conference and especially Jorgen Rasmussen, hope I didn’t embarrass you, Dude.

Might try this again sometime, just not this week …

Andrew.

PS #Andy – We saffas were gutted by the appalling refereeing decisions on Saturday, looked like it was more clear cut for you on Sunday

To report this post you need to login first.

3 Comments

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

  1. Andy Silvey

    Hi Andrew,

    excellent job, thank you.

    Next time eh 😉

    All the best,

    Andy.

    p.s. I came across a useful related OSS Note:

    Note 1716423 – SAPUI5 Browser Support for Mobile and Desktop Applications

    (0) 
    1. Andrew Jabbitt Post author

      Thanks Andy, appreciate the note. You hint at an important point: that much of this development is reusable in a mobile context. We did have this advice last week at the Mastering SAP BI conference in Jhb from Jorgen Rasmussen who demonstrated a very nice mobile app using these same technologies. His demo showed that with just a small change in style group you can serve any device with the same ‘model’.

      Regards,

      Andrew

      (0) 
      1. Andy Silvey

        Hi Andrew,

        thanks for the feedback and further information.

        What you have described, this is my humble goal of SAPUI5, that there are design patterns and code re-use-ibility and that when any connected device sends a request the backend, the backend first asks, what is the UserAgent and serves up a style sheet specific to that UserAgent.

        For the future I want to see, SAP applications running on any connected device without the need for deep re-writing of the application on a device by device basis. Of course smaller screens will be more pleasant to use with an application oriented to the smaller screen. Infact if we checkout one of Aviad’s recent blogs, we’re already there with the Mobile Portal.

        So Developers just need to tie it all together with SAPUI5 and from the beginning think in terms of, apps must be designed from the outside to handle any User-Agent from any device. Design this from the outset, into the design patterns and support for all devices will be much easier.

        Moving one step further, I think the applications running on the smart phones and tablets are more pleasing to the eye and more intuitive than traditional website designs which haven’t really changed much in the last 20 years in terms of the User interface and intereaction.

        Moving forward I want to see more web browser based applications which look more like ‘tablet/smart phone’ apps, because a lot of the table/smartphone apps are more pleasing for the eye and intuitive to use. Maybe the tablet and smartphone apps have to be more intuitive because the canvas is smaller ?

        Anyway, thanks for the feedback, that’s my few sense.

        All the best,

        Andy. 

        (0) 

Leave a Reply