Quantcast
Channel: SAPUI5 Developer Center
Viewing all 789 articles
Browse latest View live

SAP and mobile powers combined through SAPUI5 and PhoneGap

$
0
0

Last year Dagfinn Parnas wrote an article about combining SAPUI5 and PhoneGap:

Building awesome mobile apps with SAPUI5 and PhoneGap

 

Dagfinn Parnas didn't use the SAPUI5 mobile library so the full power of combining SAPUI5 and PhoneGap wasn't achieved. I haven't found anyone else on the internet make this possible either. With this blog post I will demonstrate how you can combine SAPUI5 mobile library with PhoneGap. This will make it possible for you to build native apps for all mobile platforms. You can use eclipse if you want but I will demonstrate the process without it for you, so that you will understand it deeper.

 

All the below files are available at my GitHub:

https://github.com/morganap/SAPUI5andPhonegap

 

Step 1:

Download SAPUI5: http://scn.sap.com/community/developer-center/front-end

Unzip the downloaded file.

 

Step 2:

In the SAPUI5 folder delete the following to reduce its size:

 

From sapui5-static.zip, delete:

           /test-resources/*

           /discovery/*

           /resources/sap-ui5-dbg.js

           /resources/sap-ui-core-all-dbg.js

           /resources/sap/uiext/*

           /resources/sap/service/*

           /resources/sap/makit

           /resources/sap/viz chart libraries

 

and in /resources/sap/ui/ the following library folders

           commons

           qunit

           richtexteditor

           table

           test

           ux3

 

The instruction above is from Andreas Kunz: http://scn.sap.com/thread/3287821

 

Step 3:

In the SAPUI5 folder you copy the resources folder to a place where you want to develop the web app.

(If you already have SAPUI5 version 1.10.4 and want to retrieve the resource folder check my other article

"SAP and mobile powers combined through SAPUI5 and Phonegap - make it work with new SAPUI5 version")

And then create an index.html file and a config.xml file like the picture below:

 

 

In the index.html file insert the code bellow:

 

Filename: index.html

<!DOCTYPE HTML>

<html>

       <head>

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

 

 

                    <script src="phonegap.js"></script>

              <script type="text/javascript" charset="utf-8">

 

 

                        var pictureSource;   // picture source

                        var destinationType; // sets the format of returned value

 

                        // Wait for Cordova to connect with the device

                        //

                        document.addEventListener("deviceready",onDeviceReady,false);

 

                        // Cordova is ready to be used!

                        //

                        function onDeviceReady() {

                            pictureSource=navigator.camera.PictureSourceType;

                            destinationType=navigator.camera.DestinationType;

                            navigator.geolocation.getCurrentPosition(onSuccess, onError, {enableHighAccuracy:true});

                        }

 

                        // Called when a photo is successfully retrieved

                        //

                        function onPhotoDataSuccess(imageData) {

                          // Uncomment to view the base64 encoded image data

                          // console.log(imageData);

 

                          // Get image handle

                          //

                          var smallImage = document.getElementById('smallImage');

 

                          // Unhide image elements

                          //

                          smallImage.style.display = 'block';

 

                          // Show the captured photo

                          // The inline CSS rules are used to resize the image

                          //

                          smallImage.src = "data:image/jpeg;base64," + imageData;

                        }

 

                        // Called when a photo is successfully retrieved

                        //

                        function onPhotoURISuccess(imageURI) {

                          // Uncomment to view the image file URI

                          // console.log(imageURI);

 

                          // Get image handle

                          //

                          var largeImage = document.getElementById('largeImage');

 

                          // Unhide image elements

                          //

                          largeImage.style.display = 'block';

 

                          // Show the captured photo

                          // The inline CSS rules are used to resize the image

                          //

                          largeImage.src = imageURI;

                        }

 

                        // A button will call this function

                        //

                        function capturePhoto() {

                          // Take picture using device camera and retrieve image as base64-encoded string

                            navigator.camera.getPicture(onPhotoDataSuccess, onFail, { quality: 50,

                            destinationType: destinationType.DATA_URL });

                        }

 

                        // A button will call this function

                        //

                        function capturePhotoEdit() {

                          // Take picture using device camera, allow edit, and retrieve image as base64-encoded string

                          navigator.camera.getPicture(onPhotoDataSuccess, onFail, { quality: 20, allowEdit: true,

                            destinationType: destinationType.DATA_URL });

                        }

 

                        // A button will call this function

                        //

                        function getPhoto(source) {

                          // Retrieve image file location from specified source

                          navigator.camera.getPicture(onPhotoURISuccess, onFail, { quality: 50,

                            destinationType: destinationType.FILE_URI,

                            sourceType: source });

                        }

 

                        // Called if something bad happens.

                        //

                        function onFail(message) {

                          alert('Failed because: ' + message);

                        }

 

                     // onSuccess Geolocation

                        //

                        function onSuccess(position) {

                            var element = document.getElementById('geolocation');

                            element.innerHTML = 'Latitude: '           + position.coords.latitude              + '<br />' +

                                                'Longitude: '          + position.coords.longitude             + '<br />' +

                                                'Altitude: '           + position.coords.altitude              + '<br />' +

                                                'Accuracy: '           + position.coords.accuracy              + '<br />' +

                                                'Altitude Accuracy: '  + position.coords.altitudeAccuracy      + '<br />' +

                                                'Heading: '            + position.coords.heading               + '<br />' +

                                                'Speed: '              + position.coords.speed                 + '<br />' +

                                                'Timestamp: '          +                                   position.timestamp          + '<br />';

                        }

 

                        // onError Callback receives a PositionError object

                        //

                        function onError(error) {

                            alert('code: '    + error.code    + '\n' +

                                    'message: ' + error.message + '\n');

                        }

                    </script>

                    <script src="resources/sap-ui-core.js"

                                          id="sap-ui-bootstrap"

                                          data-sap-ui-libs="sap.m"

                                          data-sap-ui-theme="sap_mvi" >

                    </script>

                    <script>

                          // create a mobile App

                          // it initializes the HTML page for mobile use and provides animated page handling

                          var app = new sap.m.App("myApp", {initialPage:"page1"}); // page1 should be displayed first

 

                          // create the first page of your application

                          var page1 = new sap.m.Page("page1", {

                              title: "SAPUI5 and Phonegap",

                              content : [new sap.m.Text({text:"Hello Mobile World!"}),

                                         new sap.m.Button({   // content is just one Button

                                             text : "Go to next page",

                                             tap : function() {

                                                 app.to("page2", "fade");   // when tapped, it triggers drilldown to page 2

                                             }

                                             }),

                                             new sap.m.Button("open_camera_button", {

                                                      text : "Open camera",

                                                      tap : function () {

                                                                 capturePhoto();

                                                      }

                                             }),

                                             new sap.ui.core.HTML({content:'<p id="geolocation">Finding geolocation...</p> <img style="display:none;width:60px;height:60px;" id="smallImage" src="" /><img style="display:none;" id="largeImage" src="" />'})

                                                                      ]}

                          );

 

                          page1.setBackgroundDesign("List");

 

                          // create the second page of your application

                          var page2 = new sap.m.Page("page2", {

                              title: "Page 2",

                              showNavButton: true,       // page 2 should display a back button

                              navButtonTap: function(){

                                  app.back();            // when tapped, the back button should navigate back up to page 1

                              },

                              content : new sap.m.Text({text:"Hello Mobile World!"})

                          });

 

                          app.addPage(page1).addPage(page2); // add both pages to the App

 

                          app.placeAt("content"); // place the App into the HTML document

                    </script>

          </head>

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

                       <div id="content"></div>

    </body>

</html>

 

Step 4

Insert the following code in the config.xml file:

 

Filename: config.xml

<?xml version   ="1.0" encoding="UTF-8" ?>

<widget xmlns   = "http://www.w3.org/ns/widgets"

                xmlns:gap   = "http://phonegap.com/ns/1.0"

                id                      = "com.intel.sample"

                versioncode = "1"

                version                 = "1.0.0">

 

 

                <name>SAPUI5 and Phonegap</name>

 

 

                <content src="index.html"/>

 

 

                <description>

                    Test application with SAPUI5 and Phonegap

                </description>

 

 

                <preference name="phonegap-version" value="2.0.0" />

                <feature name="http://api.phonegap.com/1.0/camera"/>

                <feature name="http://api.phonegap.com/1.0/file"/>

                <feature name="http://api.phonegap.com/1.0/geolocation"/>

 

 

                      <!-- for iPhone -->

                      <plugin name="Camera" value="CDVCamera" />

                      <plugin name="Geolocation" value="CDVLocation" />

 

 

                <!-- for Android -->

                <plugin name="Camera" value="org.apache.cordova.CameraLauncher"/>

                <plugin name="Geolocation" value="org.apache.cordova.GeoBroker" />

                <preference name="orientation" value="portrait" />

                <preference name="android-minSdkVersion" value="9" />

</widget>

 

Step 5

Make your files to a zip file:

 

------------------------------------------------------------------------------------------------------------------------------------

 

 

------------------------------------------------------------------------------------------------------------------------------------

 

 

Step 6

Create a free account at:

https://build.phonegap.com

This web service makes it possible to build native apps to all different mobile platforms without needing to setup different native SDK environment for every mobile platform.

 

 

Step 7

Log in with your new account:

https://build.phonegap.com

Create a new app by pressing the new app button. Then choose private, like the below picture.

 

Upload your index.zip file that you created in step 5.

 

 

Step 8

When the upload is complete this app will appear. Press the "Ready to build" button.

 

 

Now wait for the build to complete for all the different mobile platforms.

 

 

Step 9

The build will succeed for every platform except iOS and blackberry. If you want to create iOS apps you will need to enter a developer code. It will require you to have an apple computer, iPhone and an apple developer account. Blackberry complains because it thinks there are too many files uploaded. This can sure be fixed and if anyone will give it a try I appreciate it.

 

 

Press the android figure above and a download of the apk file for that platform will begin. You can download the platform you want but I will describe below for the android platform. Send the downloaded file to your android phone. You can for example email it. Before opening the file you need to allow unknown sources in your phone:

 

For android 4 devices and up:

  1. Tap Menu.
  2. Tap Security.
  3. Check the box labeled Unknown Sources.

For older android devices:

  1. Tap Menu.
  2. Tap Settings.
  3. Tap Applications.
  4. Check the box labeled Unknown Sources.

 

Step 10

Now open your apk file in your android mobile device. This will give you an option to install it. Choose to install.

 

Step 11

Open your newly created application. Play around with the app! You can test to press the camera button.

 

 

The camera opens and you take a picture. Then the picture is placed under the Timestamp text:

 

 

Step 12

The above steps show how easy it is to develop apps for all mobile platforms using SAPUI5 and PhoneGap. So what are you waiting for! Give it a try!

Unleash the power of SAP and mobiles combined!


SAPUI5 and Responsive Web Design (RWD)

$
0
0

In this article I want to examine the possibilities for Responsive Web Design (RWD) in SAPUI5. I use the latest version of SAPUI5 v 1.10.3 (this version I got when updating (Check for Updates) Eclipse yesterday). I will first explain the RWD concept and then show my own build web application developed in SAPUI5 that uses responsive design.

 

About Responsive Web Design

RWD is all about making the viewing and reading of a web application asconvenient as possible for the visitor. The same web application then looks good independent of the different screen sizes viewing the application. The RWD is a web design approach that makes it possible to only maintain one web application for all the different screen sizes. Making a separate mobile application in some cases unnecessary.

 

Below are three examples of adaptions that can be developed using RWD:

  1. In small screens, the menucan be converted to a drop down menu.
  2. In small screens, the pictures can be smaller to fit the browser size. The pictures can also be rearranged to improve the viewing experience. Or the pictures can be removed if the screen is to small.
  3. In small screens, the text sizecan be smaller and in biggerscreensbigger.

 

RWD doesn't come of itself. You as a developer need to make it happen! There are two key components to make RWD work. I will specify them below:

 

Component 1: Meta tag

You need to insert the viewport meta tag in the <head> tag. The meta tag looks like this:

    

     <meta name=”viewport” content=”width=device-width, initial-scale=1”>


You use the viewport meta tag because if you don't use it the browser will not scale to the clients browser size.

 

Component 2: CSS3 media queries

You will need to have CSS3 media queries. The media queries loads different CSS style rules depending on the device that is viewing the web application. Most often the style rules depends on the width of the browser. The media queries in itself is a component in your CSS file(s) that tells the browser what to do at different browser sizes. In media queries, you specify min-width and/or max-width. The browser built-in CSS3 logic then calculate which media queries will be executed depending on the browser size. I specify bellow some examples of media queries that can be put in a CSS file:

 

Example of media queries

 

/* Large desktop */

@media (min-width: 1200px) {  }

 

 

/* Portraittablet to landscape and desktop */

@media (min-width: 768px) and (max-width: 979px) {  }

 

 

/* Landscape phone to portraittablet */

@media (max-width: 767px) {  }

 

 

/* Landscape phones and down */

@media (max-width: 480px) {  }

 

More media queries can be found at:

http://dev.bowdenweb.com/a/css/media-queries-boilerplate.css

 

 

Responsive pictures

To get responsive pictures you will need to use the max-width property in the CSS file. It makes the pictures scale depending on the browser width. The max-width property can also be used for video, object and embed tags. The max-width doesn't work on older internet explorer browser. To make the pictures responsive in older internet explorer you need to create a separate CSS file that loads if the browser is an older internet explorer that contains the width property instead of max-width. The example below is making all the images scale depending on the browser size:

.img {

     max-width: 100%;

}

 

Responsive text

You can also make the textview scale that contains text depending on the size of the browser. I recommend it because all the text can fit the browser view or you can make it take up only some part. The example below is on a SAPUI5 textview that has the ID aboutAnimal. I use it in the media queries for the smaller browser sizes:

#aboutAnimal {

     max-width: 100%;

}


My web application

Below I will show you my example web application in different browser sizes. First I will provide you with the address of the source code available at my GitHub address:

https://github.com/morganap/responsiveWebDesign

 

Youcan try my example web application at:

https://responsivedesignp1041122trial.hanatrial.ondemand.com/ResponsiveWebDesign/

In the above link, you can test the different sizes if you shrink your web browser view. You can also visit the link above with your mobile device to see the difference.


Browser width from 961px and up

The media query looks like this: @media screen and (min-width: 961px)  { }

 

Screenshot of the web application at this width:

961pxAndUp.png

Here is the pictureput on the leftside.


Browserwidth from 769px up to 960px

The media query looks like this: @media screen and (max-width: 960px)  { }

 

Screenshot of the web application at this width:

769pxTo960px.png

Here is the pictureput on the right side.


Browserwidth from 551px up to 768px

The media query looks like this: @media screen and (max-width: 768px)  { }

 

Screenshot of the web application at this width:

551pxTo768px.png

Here is the menureplacedwith a drop down box. The text is madesmaller.

The text is made so that all the space width is allocated.


Browserwidth from 321px up to 550px

The media query looks like this: @media screen and (max-width: 550px)  { }

 

Screenshot of the web application at this width:

321pxTo550px.png

The text is madesmaller.


Browserwidth up to 320 px

The media query looks like this: @media screen and (max-width: 320px)  { }

 

Screenshot of the web application at this width:

0pxUpTo320px.png

The text is madeevensmaller.

 

Mobile device browser
I tested my web application on my mobile device to seehow it lookedthere.


Screenshots (I press the Menu button and choose Giraffes):

mobile1.pngmobile2.pngmobile3.png


 

Conclusion:

The SAPUI5 framework is easy to adapt to different browser sizes thanks to its support of CSS3. My opinion is that there is some work to make the responsive web application look good. But I think the work is similar for all the different frameworks out there. I hope with this article I can help developers get some code examples and tips on the way of creating responsive web applications in SAPUI5.

 

By the way!

Another concept of RWD is the fluid proportion-based grids. This have SAP made available out-of-the-box with the layout component ResponsiveFlowLayout. Fluid proportion-based grids are layout grids that deform depending on the users browser size. See this link (you will need to have a SAP account):

https://sapui5.netweaver.ondemand.com/sdk/#content/Controls/Layout/ResponsiveFlowLayout.html

Are you getting "No data" in your SAPUI5 table?

$
0
0

I've been pulling my hair out for the last few hours trying to work out what was wrong with my SAPUI5 demo application. I finally worked it out and want to quickly share what the problem was in case others fall into the same issue.

 

Background

Back at the end of last year I had downloaded the SAPUI5 Trial version (at the time version 1.4.3) and had written a very basic MVC demo app to get familiar with how things worked in SAPUI5. I had the usual issues with CORS (Cross Origin Resource Sharing) - you will find lots of posts about solutions for that in the discussions on SCN, but finally got a basic example working, calling an ODATA service from the SAP Enterprise Workplace system. All was good, I was a happy chap . Then things got busy, and I only came back to this example a few days ago when I wanted to get the same example working from a "real" SAP system where we recently installed the SAP UI Add-On 1.0 and Gateway.

 

Problem

So I wanted to keep it simple, I used the same method to create a new SAPUI5 application to read a simple ODATA service from my SAP system and put the data into a table. Everything looked the same, I could see (in the developer tools) the first request being sent to the ODATA service on the SAP server and I could see the response coming back, it all looked good, but I was getting "No data" in my table...

 

2013-04-18_0938.png

So what was going on? I spent a while checking my code for stupid syntax mistakes... nothing. I had no idea. As far as I could tell the only difference between the new and the old app was the version of the SAPUI5 I was using. The version on my SAP server was 1.8.4 (the old one was 1.4.3). I then decided to set up a direct comparison. I updated my local Tomcat server with both the 1.8.4 and the older 1.4.3 versions of SAPUI5 and ran them side by side. I then switched the bootloader statement in my app to use one or the other. What I found was that when I used the 1.4.3 version my code worked fine and the table was populated with data:

2013-04-18_1027.png

When I then switched to use version 1.8.4 it stopped working and I got "No data" again. So I concluded it must be the version.

 

Solution

So how to fix it? I could find lots of posts about not getting any data into tables, but mostly it was due to the CORS issue, I knew that wasn't the problem. So I went to the release notes in desperation . Now reading release notes isn't that much fun, but I started with version 1.4.3 and worked up to see if anything might mention a change that was causing the problem... and there it was...

 

2013-04-18_0948.png

CHANGE: Databinding syntax changed, so that absolute bindings now must have a leading slash. For compatibility reasons, method setLegacySyntax() can be used to enable the old binding syntax.

 

What the hell I thought, lets try to add a forward slash to the oTable.bindRows("/SOHeaders") statement and what do you know, suddenly it worked and no more "No data"!

 

Here is a little video that shows the problem and the solution:

 

 

So if you are trying out SAPUI5 and you are following some of the older tutorials or blog posts from people here on SCN and you are getting "No data" in your tables it might be a CORS issue but it might also be that you are missing the leading slash "/" in your binding statement. I hope this post will save you some time and let you get on with more interesting bits of SAPUI5.

 

Please share your comments and thoughts below.

Thanks,
Simon

SAP and mobile powers combined through SAPUI5 and Phonegap - make it work with new SAPUI5 version

$
0
0

In my article "SAP and mobile powers combined through SAPUI5 and Phonegap" I showed how to create a mobile application with SAPUI5 mobile library and Phonegap. In that article I used SAPUI5 version 1.8.4. The current version of SAPUI5 is 1.10.4. The problem is that when upgrading to this version you will not get the resource folder described in my previous article. I will bellow describe how you can get the resource folder for version 1.10.4. Then you can go back to my previous article and continue to build the mobile application but with the new functionality of SAPUI5 1.10.4.

 

Step 1

In Eclipse you open the project of the mobile SAPUI5 application you are building. Then you open the Libraries and "SAPUI5 Core Libraries" as shown in the picture bellow.


picture1.png

In the picture you see which libraries that are included in your SAPUI5 application. These files have a path in there names, example for me it stands C:\Users\cla_morape\Documents\SAPUI5\eclipse\plugins. Go to that folder.

 

Step 2

In the bellow picture I have opened the folder described in step 1.

picture2.png

In this folder you copy all the files that is described in "SAPUI5 Core Libraries" in step 1 into a temporary folder. For me it looks like this when I have done it:

picture3.png

Step 3

You need to have Java SDK installed to extract the content of the jar files.

 

Step 4

Open the command prompt. In Windows press the start button and type cmd, then press enter. In the command prompt you need to navigate to the temporary folder you created in step 2. When you are there you need to do an unpack command on each of the jar files in that folder.

The jar command: jar xf jar-file-name

For example, I typed:

picture5.png

In the temporary folder I now have two new folders: libraries and META-INF.

 

If the jar command described above don't work you may need to add the path to the java bin folder to your environmental variables as shown bellow (your path to the Java folder may be different):

picture4.png

 

Step 5

In the temporary folder open the folder META-INF. In that folder you will have a folder called resources. This folder is the one you where looking for! Use this resource folder in my other article "SAP and mobile powers combined through SAPUI5 and Phonegap" and start from the step 2 in that article.

 

Good luck! 

 

Thanks Shiang Li for notifying me about this issue!

 

Kind regards

Morgan Apelqvist

Working with OData Dates and Times

$
0
0

When consuming Gateway services in JavaScript the task of working with dates and times is made even harder because of the different representations the objects take. In this blog I will highlight how Gateway OData dates and times are represented in both JSON and JavaScript and show by example how to use these values in SAPUI5 with the JavaScript Date Object and the Class sap.ui.core.format.DateFormat.

 

TLDR: You can use sap.ui.core.format.DateFormat to format and parse date and time objects when working with Gateway services, see http://jsbin.com/irewuq/9/edit for an example.

 

Below is the formatted JSON representation of Gateway Entity, similar to what you get using the Flight Service in the Demo Gateway system. eg http://gw.esworkplace.sap.com/sap/opu/odata/IWBEP/RMTSAMPLEFLIGHT_2/FlightCollection?$format=json

"FlightConnectionID": "0017",
"FlightDate": "/Date(1354665600000)/",
"FlightDetails": {    "ArrivalInDays": 0,    "ArrivalTime": "PT14H01M00S",          "DepartureAirPort": "JFK",          "DepartureCity": "new york",          "DepartureCountryCode": "US",          "DepartureTime": "PT11H00M00S",          "DestinationAirPort": "SFO",          "DestinationCity": "SAN FRANCISCO",          "DestinationCountryCode": "US",          "Distance": "2572.0000",          "DistanceUnit": "SMI",          "FlightTime": 361,          "FlightType": "",          "__metadata": {                "type": "RMTSAMPLEFLIGHT_2.FlightDetails"    }

 

Highlighted below are Date and Time passed in this service

"FlightDate": "/Date(1354665600000)/",  - JSON Date Object
"DepartureTime": "PT11H00M00S", - XSD Duration

 

FlightDate is represented as a JSON Date object, the value is the date in milliseconds since Unix Epoch.

 

Unix EPOCH time = Date(0) = Thu Jan 01 1970 00:00:00 GMT, this value is handy to know if your going to work with dates. http://en.wikipedia.org/wiki/Unix_time

 

DepartureTime is represented as an XSD:Duration Date Type

The letters in PT11H00M00 - P: Period, T: Time, H: Hours, M: Minutes see http://www.w3schools.com/schema/schema_dtypes_date.asp

 

Luckily if you use the ODataModel, datajs the OData library SAPUI5 uses has regular expressions and code logic which parses these values into JavaScript for us. Below is how this Entity looks parsed to JavaScript.

odata_date1.png

ODataModel values highlighted

FlightDate : Wed Dec 05 2012 11:00:00 GMT+1100 (AUS Eastern Daylight Time)  
DepartureTime : { __edmtype: "Edm.Time", ms: 39600000}  

 

FlightDate looks like a string, it is in fact the string representation of a JavaScript Date Object

 

The JavaScript Date Object supports the following ways for instantiating a date, if you are in the AEDT timezone then the following values will be equal.

var a = new Date('Wed Dec 05 2012 11:00:00 GMT+1100 (AUS Eastern Daylight Time)');
var b = new Date(1354665600000);
var c = new Date('2012/12/05');
a.getTime()===b.getTime()&& a.getTime()===c.getTime()

date.getTime() returns the number of milliseconds since Epoch.

 

Important to note is the Timezone offset when comparing dates, was +1100 AEDT in December, today its +1000 due to daylight savings.

new Date( )  = Sun Apr 28 2013 14:05:52 GMT+1000 (AUS Eastern Standard Time)

 

To get a consistent Timezone offset use the one from Epoch

var TimezoneOffset = new Date(0).getTimezoneOffset(); // -660 minutes

 

DepartureTime is a millisecond value wrapped in a edmtype object.

39600000/3600000 = 11 hours 00 min  // 3600000 is the number of milliseconds in an hour 60 minutes *60 seconds *1000 milliseconds

 

We can use the value in a javascript date object and it will give us the time since Epoch

new Date(39600000).toUTCString() = Thu, 01 Jan 1970 11:00:00 GMT
new Date(39600000).getUTCHours() = 11


SAPUI5 provides the Class sap.ui.core.format.DateFormat that can be used with JavaScript Date Objects for formatting and parsing dates and times.

 

The example i'll give is formatting dates and times to formats you may want to use in a mobile application. eg

date1.pngtime1.png

 

There is not much to it if you handle everything in UTC milliseconds, to do this we add the timezone offset when formatting and remove it when parsing.

 

// SAPUI5 formatters
var dateFormat = sap.ui.core.format.DateFormat.getDateInstance({pattern : "dd/MM/yyyy" }); 
var timeFormat = sap.ui.core.format.DateFormat.getTimeInstance({pattern: "KK:mm:ss a"});        

// timezoneOffset is in hours convert to milliseconds
var TZOffsetMs = new Date(0).getTimezoneOffset()*60*1000;

// format date and time to strings offsetting to GMT
var dateStr = dateFormat.format(new Date(FlightDate.getTime() + TZOffsetMs)); //05-12-2012 
var timeStr = timeFormat.format(new Date(DepartureTime.ms + TZOffsetMs));  //11:00 AM

//parse back the strings into date object back to Time Zone
var parsedDate = new Date(dateFormat.parse(dateStr).getTime() - TZOffsetMs); //1354665600000   
var parsedTime = new Date(timeFormat.parse(timeStr).getTime() - TZOffsetMs); //39600000

*Note to SAPUI5 developers DateFormat.format has a to UTC flag, DateFormat.parse could use a from UTC flag.

 

The following is a list of the pattern elements in the DateFormat class, use them to derive the date and time formats you need.

/**
 * Pattern elements
 */
sap.ui.core.format.DateFormat.prototype.oStates = {          "G": "era",          "y": "year",          "Y": "weekYear",          "M": "month",          "w": "weekInYear",          "W": "weekInMonth",          "D": "dayInYear",          "d": "day",          "F": "dayOfWeekInMonth",          "E": "dayNameInWeek",          "u": "dayNumberOfWeek",          "a": "amPmMarker",          "H": "hour0_23",          "k": "hour1_24",          "K": "hour0_11",          "h": "hour1_12",          "m": "minute",          "s": "second",          "S": "millisecond",          "z": "timezoneGeneral",          "Z": "timezoneRFC822",          "X": "timezoneISO8601"
};

 

I have shown you the JSON and JavaScript representations Gateway services have for date and time, given an overview of how to use some of the functions of the JavaScript Date Object, shown an example of how I use the sap.ui.core.format.DateFormat Class to format values for a mobile application which integrates with Gateway services. All that's left is to share working code http://jsbin.com/irewuq/9/edit.

How to Deploy HTML5 applications to 7.3 portal

$
0
0

From the very beginning since I started working with HTML5, I was always looking for a way to integrate HTML5 pages in the portal and test these out on actual mobile devices like smartphones and tablets. This blog explains in an easy set of steps how we can build a portal application project in NWDS and include our HTML5 page(s) within this project and deploy it to the portal.

 

Since as of 7.30 SP08 there is no explicit iView template provided by SAP for creating iViews directly out of HTML5 applications, we are using the portal application project approach.

 

The portal and NWDS version I am using for this is NW 7.30 SP08. It is advisable to try this out on NW 7.30 SP07 minimum, since in SP07 Smartphone Framework Page is provided out-of-the-box and SP08 onwards Tablet Framework Page is provided out-of-the-box by SAP.

 

Follow the below steps to deploy your HTML5 page(s) to your portal.

 

1. In NWDS, create a project of type Portal Application.

 

image.png

 

2. Give a project name and click Finish.

 

image.png

 

3. Expand the project node and in the distfolder create a folder called html.

 

image.png

image.png

image.png

image.png

   We will create our HTML5 page(s) within this html folder.

 

4. Right click on the html folder and create the HTML page(s).

 

image.png

image.png

image.png

image.png

 

5. Code the HTML5 page according to your requirements in the HTML editor.

 

image.png

6. Now we need to create a component within our portal application project. For this right click on the project and select New-> Other.

 

image.png

 

7. Then select Portal Application-> Create a new Portal Application Object.

 

image.png

 

8. Click Next on the following screen, the intended project will be selected by default.

 

image.png

 

9. In the next screen expand Portal Componentand select AbstractPortalComponent and click Next.

 

image.png

 

10. Enter values for Name and Package Namefor the Portal Component. Then click Finish.

 

image.png

 

11. Now in the project structure you will find the AbstractPortalComponent object is created within the src.core folder.

 

image.png

 

12. In this component’s doContent method we will write the code to call our HTML page. Write the below code in the doContentmethod. We are just

     declaring a variable of IResource type and including our HTML page within the response using the includemethod.

    

     Assume that TestHtml is the name of our HTML5 page.

 

        IResource myHtml = request.getResource(IResource.STATIC_PAGE, "html/TestHtml.html");

                 if(myHtml.isAvailable()) {

                response.include(request, myHtml);

                                   return; 

        }

 

                 String url = myHtml.getResourceInformation().getURL(request);

         response.write("Resource is not available: <a href='"+ url + "'>" + url + "</a><br>");

 

13. Now we have to deploy this component to the portal. For this first we will export this project as an EAR file. For this right click on the project and select the

      option Export from the context menu.

 

image.png

 

14. Select the option SAP NetWeaver Portal-> EAR File and click Next.

 

image.png

 

15. Select Nexton the following screen, the project will be selected by default.

 

image.png

 

16. Click Finishon the next screen.

 

image.png

 

17. Now you will be able to see the EAR file in the project structure.

 

image.png

 

18. Now we will deploy this EAR file to our portal. For this first make sure that the portal system has been added and set as the default system

      under Window-> Preferences-> SAP AS Java.

 

image.png

 

19. Now navigate to the Deploy view by clicking Window-> Show View-> Other.

 

image.png

 

20. Now expand the node Deploy Viewand select Deploy View.

 

image.png

 

21. In the deploy view, right click on the option External Deployable Archivesand select Add.

 

image.png

 

22. From your file system, navigate to the path where the project lies and select the EAR file that we created earlier.

 

image.png

 

23. The EAR now appears under External Deployable Archives.

 

image.png

 

24. With the EAR file selected, select the Deploybutton (or right click on the EAR file and select the option Deploy from the menu).

 

image.png

 

25. Now you will be able to view the deployment progress in the lower right corner.

 

image.png

 

26. You will get a confirmation message upon successful deployment.

 

image.png

 

27. Now login to your portal and navigate to Content Administration-> Portal Content Management and expand the node Portal Applications.

    

28. Scroll down until you have located your Portal Application project. Expand the node and you will find your AbstractPortalComponent.

 

29. Right click on it and select Copy from the context menu.

 

30. Now navigate to your desired folder under Portal Contentand right click on it. Select Paste as PCD Objectfrom the context menu.

 

31. Give a name (this will be the iView name) and ID (optional) and click Nextand Finish.

 

Thus we have created an iView for the HTML5 page. This iView can be used according to your requirement in your desired mobile Roles(s).

Spring Webflow for SAPUI5 view navigation and state management

$
0
0

Introduction

 

     A non-trivial single page application will have to manage state (model) manipulation and implement view navigation between states. Although it is technically possible to do this on the client's side, i.e. with JavaScript and local storage introduced by HTML5, this might not be the optimal approach. Considering that a typical application will already have some sort of heavy-duty logic implemented in Java on the back-end, we may, as well, take advantage of the existing flow management frameworks available for Java to maintain state information and conversation logic needed to implement a relatively complex view navigation.

One such excellent framework is Spring Webflow (SWF). It allows for declarative style specification of view-states, action states, decision states and transition between them based on the events (request parameters). It also makes available a hierarchy of scopes: session, flow, flash, request, view where to store the flow related variables (state shared by the views).

     The idea behind the proof-of-concept application discussed in this article is to show how one can use SWF with a simple SAPUI5 application which has following characteristics: it's a single-page application, i.e. one HTML page with only AJAX calls (no page reloads), starting state ("step1") allows transition to the second state ("step2") with some user-defined parameters, there are two transitions from the second state, back to the first state and to the finish state ("done") which ends the flow.

 

Spring Webflow Setup

 

     We'll be creating a simple Maven-driven SWF application (see the examples from sprig-webflow-samples for typical setup) as a starting point. Note that SWF already includes the Dojo library for decorating front-end controls as widgets (in itself a wonderful front-end framework). But, since we are using SAPUI5 Javascript framework, we can exclude the artifact containing Dojo distribution from our SWF dependency (artifact id: "spring-js-resources"). Below, there is a general overview of the application's files.

 

Capture_d_écran_10.05.13_22_39.png

     There is a Spring root application context, a context for Spring MVC and SWF beans loaded by the DispatcherServlet (mvc-dispatcher-servlet.xml). SWF is setup as usual with the following definition of the required flow registry and flow handler adapter beans (other beans are omitted).

 

<webflow:flow-registry id="flowRegistry">     <webflow:flow-location id="demo" path="/WEB-INF/flows/flow.xml"/></webflow:flow-registry><bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">    <property name="flowExecutor" ref="flowExecutor"/>    <property name="ajaxHandler">        <bean class="ch.unil.demo.swf.JsonHandler"/>    </property></bean>

 

     The ID of the flow will be used to start the flow by issuing the initial AJAX call to "/demo" URL. SWF allows specifying a custom implementation of AjaxHandler interface which decides whether to treat each request as an AJAX request. Our implementation simple looks for the "application/json" content type.

 

public class JsonHandler implements AjaxHandler {    @Override    public boolean isAjaxRequest(HttpServletRequest request, HttpServletResponse response) {        boolean isAjax = false;        if (request.getContentType().equals("application/json")) {            isAjax = true;        }        return isAjax;    }      @Override    public void sendAjaxRedirect(String targetUrl, HttpServletRequest request, HttpServletResponse response, boolean popup) throws IOException {    }
}

 

     The flow itself is quite simple. It defines two view-states and one end-state, as well, as the relevant transitions.

 

<view-state id="step1" view="/WEB-INF/flows/view_model_json.jsp">    <on-entry>        <evaluate expression="viewModelController.updateViewModelData(flowRequestContext)"/>    </on-entry>    <transition on="next" to="step2"/></view-state>  <view-state id="step2" view="/WEB-INF/flows/view_model_json.jsp"><on-entry>    <evaluate expression="viewModelController.updateViewModelData(flowRequestContext)"/></on-entry><transition on="finish" to="done"/><transition on="back" to="step1"/></view-state><end-state id="done" view="/WEB-INF/flows/done.jsp">

 

     All of the state management logic is encapsulated within a POJO, ViewModelController, which updates three view-scope variables upon each view-state entry, depending on the current state and the transition event. The variable "flowExecutionUrl" contains the URL with the execution key for the current state (it is automatically available in any JSP-backed view in SWF). This is the URL to which all of the AJAX requests should be sent, The variable "stateId" identifies the current state of the flow ("step1", "step2", "done"). The variable "modelData" contains a JSON data used to construct a JSONModel for the dynamically created JSView of the SAPUI5 front-end. The data is serialized using Jackson ObjectMapper object wired into the controller from the root application context. The POJOs: StepOne, StepTwo, and Done (extensions of ModelData) are simply used to serialize JSON string containing model data.

 

public class ViewModelController {    private ObjectMapper jacksonMapper;    public void setJacksonMapper(ObjectMapper jacksonMapper) {        this.jacksonMapper = jacksonMapper;    }    public void updateViewModelData(RequestContext requestContext) throws IOException {        ModelData modelData = null;        // get the current state        String curStateId = requestContext.getCurrentState().getId();        // create or update model data for the view based on the current state        if (curStateId.equals("step1")) {            StepOne data = new StepOne();            if (requestContext.getCurrentEvent()!=null){                 // back from step2                data.setText("Back from step 2. Enter a value for the output parameter.");            }            else {                // flow start                data.setText("Start of the flow. Enter a value for the output parameter.");            }            modelData = data;        } else if (curStateId.equals("step2")) {            StepTwo data = new StepTwo();            data.setText("Parameter from step 1: " + requestContext.getRequestParameters().get("outputParam"));            modelData = data;        } else {            // end-state            Done data = new Done();            data.setText("The end-state: done. Goodbye.");            modelData = data;        }        // serialize model data as JSON stirng and store it in the view scope variable        requestContext.getViewScope().put("modelData", jacksonMapper.writeValueAsString(modelData));    }
}

 

     Each of the two flow's view-state uses a generic JSP (veiw_model_json.jsp) to expose the view-scoped variables as JSON content returned with each AJAX call.

 

{    "flowExecutionUrl": "${flowExecutionUrl}",    "stateId": "${flowRequestContext.currentState.id}",    "modelData": ${modelData}
}

 

 

SAPUI5 front-end

 

     On the front-end side, we have a standard SAPUI5 web application set up, with the default "index.html" point of entry. Note that for the root application path mapping to work as expected (for URL paths like "/" or "/index.html") you should have the following declaration in your Spring MVC setup.

 

<mvc:default-servlet-handler/>

 

     This uses a helpful "mvc" namespace to setup forwarding to the container's default Servlet. The welcome file is straight forward. It contains the standard bootstrap script for the SAPUI5 libraries (which, of course, should be available in the "/WEB-INF/lib" folder), the main executable script "app.js" for the application logic, and the usual div with "content" ID attribute where each view's controls will be placed at. Here is "app.js" file.

 

var flowExecutionUrl = "/demo?mode=embedded",    currentView,    header;  
function ajaxCall(eventId, params, context) {    if (!params) {        params = {};    }    if (!context){        context = this;    }    if (eventId) {        params._eventId = eventId;    }    return jQuery.ajax(flowExecutionUrl, {        type: "GET",        data: params,        dataType: "json",        contentType: "application/json",        cache: false,        context: context    });
}

function updateMvc(executionUrl, stateId, modelData) {
    var controller, model, view;    // remove old view, if needed    if (currentView) {        currentView.destroy();    }    // update current flow execution url for successive calls    flowExecutionUrl = executionUrl;    // create controller for the current state    controller = sap.ui.controller("demo." + stateId);    // create new JSON model using the provided model data and register it with the controller    model = new sap.ui.model.json.JSONModel();    model.setData(modelData);    controller.model = model;    // create a view for the current state    view = currentView = sap.ui.view({        type: sap.ui.core.mvc.ViewType.JS,        viewName: "demo." + stateId,        controller: controller    });    view.placeAt("content");
}  
// register custom module path
jQuery.sap.registerModulePath("demo", "js/demo");

// execute an ajax call to start the flow and display the view for the start state
ajaxCall().done(function (response) {
    updateMvc(response.flowExecutionUrl, response.stateId, response.modelData);
});  
// create application header
header = new sap.ui.commons.ApplicationHeader({    logoText: "Demo: Spring Webflow and SAPUI5",    displayWelcome: false,    displayLogoff: false
});
header.placeAt("header");

 

     Couple of things to notice here. First, the URL for the initial AJAX call (see "flowExecutionUrl" variable declaration) to start the flow should mach the ID of the flow ("/demo"), as we have stated above. Also, since we are dealing with AJAX driven application, we need to start the flow in the embedded mode (hence the query parameter. This (together with our custom AjaxHandler) set's up the SWF to properly handle AJAX requests without issuing it's usual redirects which allows for "the partial page updates."

     The script declares a helper function which uses jQuery's "ajax()" functionality to communicate with the SWF by sending "GET" requests (note that "POST" requests do not work with this setup) to the current flow execution URL with the given "_eventId" parameter. Another helper function, "updateMvc()", is intended to be called upon a successful resolution of the deferred returned from the AJAX call. It updates the current flow execution URL (to reflect the state change), creates new controller and JSView objects by appending the state ID to the custom "demo" module, so that, for example, if "stateId" is "step1" (as declared in "flow.xml") the controller created will reference the "demo/state1.controller.js" file, while the corresponding view is described in the "demo/state1.view.js" file. Once the controller is instantiated, but before the creation of the view, we can pass an instance of JSONModel to it to be bound to the view during the "onInit" phase. The model is created with the "modelData" object retured from the SWF for the given state.

     The views and controllers are all pretty standard, just calling the helper functions during UI event handling. For example, when user clicks "Next" button on the first view (view-state "step1"), the controller executes the following code.

 

next: function (outputParam) {        ajaxCall("next", {            outputParam: outputParam        }).done(function (response) {                updateMvc(response.flowExecutionUrl, response.stateId, response.modelData);            });    }

 

Observing the application at the runtime

 

     When the root path of the application is accessed at "/index.html" an AJAX call to "/demo?mode=embedded" is executed. We can see that the flow is started with the new execution for the current client and the initial state ("e1s1").

Capture_d_écran_11.05.13_11_23.png

Capture_d_écran_11.05.13_11_27.png

     When the "Next" button is clicked, the application transitions to the state "step2" (the call is executed with "_eventId=next" query parameter).

Capture_d_écran_11.05.13_11_35.png

Capture_d_écran_11.05.13_11_38.png

 

Conclusion

 

     Using Spring Webflow to manage state information (creating and updating JSON model used in views), as well as, declaratively specifying state transitions based on well defined events in the single-page SAPUI5 application can be an interesting solution, especially if the application already requires the use of Java on the server side. One possible approach to combining SAPUI5 MVC and SWF, described in this article, is to expose view-scoped variables (state ID, model data) as JSON values via a generic JSP used in the view-states of the flow. The generated JSON, then, is used as a response to the AJAX calls to the execution flow URL with transition event IDs and output parameters specified as query parameters. Upon receiving the response from the server, the application should instantiate an controller and a view with appropriate names based on ID of the current state. The model data from the response can be used to create a JSONModel which can then be registered with the controller and bound to the view.

     We have only scratched the surface of what Spring Webflow can offer. Its main advantage is that it provides a clear, declarative approach to state definition and management. But since it plugs in well with the rest of Spring's driven architecture there are multitude of other functionalities available to the programmer, once the decision to use SWF had been taken. To name a few: there is Spring Security for securing flows, using Spring EL in flow definitions, bean validation, unit testing the flows and more.

Is this cool or what???

$
0
0

SAPUI5 for tablet, smartphone and desktop

Wow! SAP has today released the next (compatible, of course) version of SAPUI5, our HTML5 controls library, that SAP is using as the standard User Interface Control library in all their future applications that need a "consumer grade" User Experience, whether it is on desktop, tablet or smartphone! It's the basis for SAP's User Experience strategy. Now we have released version 1.12 officially and it is ready for download on the SAP Community Network Development Center. If you want a copy, here we go:

Now why am I so excited about this new version? Well, that's easy:

 

First, SAPUI5 per se is an absolutely cool and great UI framework. It's based on open source and open standards like JQuery, HTML5, JavaScript, CSS, LESS and others, it's extensible ("if we don't have something in stock, add an open source or 3rd party control) as a core framework and has been built from ground up to best support modern browsers like Google Chrome, Apple Safari, Firefox and Microsoft IE 9 and 10 (for details, check this out). It is independent of the backend system, whether it is SAP Application Server ABAP, or SAP Application Server Java, or HANA Cloud Platform -- it just doesn't matter. We've effectively decoupled the lifecycle of the UI, which changes often, from the backend system release, which changes more seldom. It is optimized to consume REST/OData services as exposed by e.g. SAP Netweaver Gateway, SAP HANA Cloud Gateway or SAP HANA itself. So you can connect it basically to any SAP system!

But with the newest version we've done the next major step: We are no providing two "flavors" of SAPUI5 based on the same programming model and tools:

  1. The full-blown desktop version with a vast set of UI controls to easily and quickly build state-of-the-art Web UIs
  2. The tailor-made mobile version that supports not only Apple iOS, Google Android, RIM BlackBerry and Microsoft Windows Phone 8 for both tablet and smartphone form factors, but also supports to run the tablet versions on desktop browsers (even for "old" IE8 with a few degradations) -- a capability that is absolutely unique in the market!

If you want to see SAPUI5 v.1.12 in action and what SAP has built with it, check out SAP Fiori, a collection of consumer-grade productivity applications for tablet, smartphone and desktop as announced at SapphireNow 2013 in Orlando.


The more detailed list of new features added with V1.12 reads nicely as well:

  • Components: One can bundle UI5 related objects like modules, views, controllers, etc. in components
  • New view type: Declarative HTML, this is also included in SAPUI5 Eclipse tools
  • New desktop controls like
    • Form, ResponsiveLayout, Autocomplete, Collection Inspector, FormattedTextView
    • Notetaker, DateRangeSlider, SplitButton
  • Best practices mobile demo application
  • All mobile (sap.m) controls which are not experimental support Blackberry 10
  • New mobile controls like
    • SplitApp, PullToRefresh, MessageToast, MessageBox, ActionSheet, InputDateTime
  • New experimental mobile controls like
    • TileContainer, TabularList, Shell, Accept/Reject Switch, GrowingList, IconTabBar, ActionSheet
    • DateTimeInput, Link, ObjectHeader, TextArea, URLHelper
    • Calendar, ProgressIndicator, TabContainer
  • New mobile features
  • Configurable/themable background images for App, SplitApp, Shell (experimental)
    • Swipe-for-action in Lists
    • Mobile library comes with new experimental Blue Crystal theme
    • Mobile library with Blue Crystal theme runs on smart phones, tablets and desktops. This is only an experimental feature
    • Charts in sap.viz library
      • Basic touch support
      • New charts: Dual Bar, Dual Line, Dual Combination, Dual Column, Dual Stacked Bar
    • New Icon fonts / pool
    • sap.ui.Device: API for device and feature detection and media query support
    • Calculated fields in databinding, i.e. bind control properties to more than one data property

 

And our new WYSIWYG, browser-based UI creation tool with dozens of pre-designed templates to start with, SAP AppDesigner, is soon to be released as well...

I can only recommend you to download this latest release as a free trial from SCN Developer Center and check it out! There's tons of documentation, tutorials, sample code snippets and demo applications

Dear SAPUI5 team! You really rock! Thanks! :-)


Architecting an SAP Fiori deployment

$
0
0

There’s been a great buzz this week following the SAP Fiori announcement. Do check out this siteto find out what it’s all about if you haven’t seen it yet but in a nutshell Fiori is a collection of consumer-grade productivity apps for common enterprise scenarios that work seamlessly across smartphones, tablets and PCs.


 

From a technical perspective, each SAP Fiori app consist of a “UI component” and an “integration component”. The UI component is an SAPUI5 application and the integration component provides the underlying SAP NetWeaver GatewayOData service.

 

I’ve been lucky enough to be involved in two projects recently that are based on a very similar architecture so here are initial thoughts on how to architect a Fiori app deployment. Please do add your comments and experiences below, especially if you’ve participated in the Fiori ramp-up programme.

 

Key functions

To start with, I'll list the key functions that an SAP Fiori architecture needs to provide. This is in addition to the relevant SAP ERP processes that I assume to be in place and fully configured:

  • Serve the SAP NetWeaver Gateway OData Services
  • Serve the SAPUI5 application
  • Authenticate the user
  • Provide internal and external access
  • Help users to discover the Fiori apps

 

 

In its simplest form all these functions can be provided by a single SAP NetWeaver ABAP application server that is accessed from the internal network or over an existing VPN connection. In real life most deployments will end up being  more complex though.

 

 

In the next step, let’s look at the options for these five functions in more detail - starting with the NetWeaver Gateway services.

 

 

Serve the SAP NetWeaver Gateway OData Services

With SAP NetWeaver Gateway there are basically two deployment options. SAP NetWeaver Gateway can either be installed as an ABAP Add-On “embedded” into your SAP ERP system or it can be deployed as a “standalone” instance. An embedded installation is only an option if your ERP system meets the SAP NetWeaver Gateway prerequisites. Running SAP NetWeaver Gateway as a standalone instance adds additional overhead but comes with the advantage that it can be upgraded independently from your core systems and it can form a single access point for multiple backend systems.


 

What can be  confusing initially is that in the standalone scenario the SAP Fiori integration components need to be deployed into the backend system. The reason is that although the OData service is served by SAP NetWeaver Gateway, the service logic itself is executed  by the “Backend Event Publisher” (IW_BEP) on the backend system.

 

 

Serve the SAPUI5 application

The natural home for the “UI component” of the SAP Fiori apps is alongside the SAP NetWeaver Gateway Services, but it could also go into any other SAP NetWeaver ABAP Application server that has the “SAPUI5 for NetWeaver Add-On” installed. Such a split installation then would need to be fronted by a shared reverse proxy server to avoid same origin policyissues.

 

 

Authenticate the user

Fundamentally SAP Fiori users need to authenticate against the UI component. Once that is accomplished the user’s identity can be propagated (e.g. via SSO2 tokens) to the Gateway service which then uses a trusted connection to connect to the ERP system. For this to work as intended, the user name needs to be consistent across all three components. If the UI component, the integration component and the ERP system are all on the same instance than that will naturally be the case. In distributed scenarios however user details will need to be replicated – either via SAP Central User Administration (CUA) or from your central identity store.

 

 

Where the variations come in is how the initial authentication takes place and there is a whole raft of different options:

  • User name and password
  • X.509 client certificates
  • SAML tokens generated by SAP IdP or another SAML Identity Provider
  • SSO2 tokens generated by an SAP NetWeaver Portal instance
  • Other single-sign on providers

 

 

In my book this degree of openness is a real strength of the SAP Fiori architecture, but needs some thought in advance to get it right. If authentication is by user name and password it tends to be a wise move to link into a central identity store to make sure your users can actually use the new apps and to keep your support cost down.


 

Provide internal and external access

Remember the lady in the Fiori promotion video checking a purchase order from her smartphone in the fitness club? To make that happen any Fiori UI components, integration components and potentially your identity provider need to be accessible from the internet. I bet that whoever is responsible for the security of your corporate network and data wants to have a say how this is going to be achieved so make sure to discuss this topic as early as possible. Again the SAP Fiori architecture isn’t prescriptive of how to do this which will help to fit in with existing policies and infrastructure at the network edge.


 

For mobile device the SAP Mobile Platform (SMP) can also be a viable access path if you wrap the Fiori apps into small hybrid apps. In that case SMP can add an additional layer of security with its device registration features, but all of that is purely optional.


 

Helping users to discover the Fiori apps

Now that the apps are up and running think about how your users will be able to discover the Fiori apps. Being creative with how to promote the apps is well worth the effort to drive user adoption. Adding the Fiori home page to your intranet could be a good starting point. Direct links to each app could also be promoted via your enterprise app catalogue or they could be pushed down automatically to any corporate managed mobile device via a mobile device management solution. For the many approvals scenarios in the Fiori app portfolio, why not add the links directly into the respective reminder emails that are being sent out by the underlying workflow?


 

Sizing implications

The final point to consider is sizing the required infrastructure. I won’t go into details in this blog, but a good starting point would be to get to the bottom of the intended target audience. How large is the target audience? How many of them are already using the functions offered by the Fiori apps via a different channel? What is the expectation of usage within the corporate network vs access from external? There is also tons of good advice on SCN now regarding sizing SAP NetWeaver Gateway.

 

If you want to dive deeper, check out this SAP Help page which holds the product documentation for SAP Fiori.

 

Many thanks go to my colleagues DJ Adams and Brenton O’Callaghanfor contributing to this blog.

SAP Netweaver Gateway CRUD Operation using SAPUI 5

$
0
0

Based on document Sample UME Application using SAPUI5 and SAP Gateway - Part II

I like to Update code for the sapui5 1.8.4

 

For Update

once model is set with service url .......

       var oModel = new sap.ui.model.odata.ODataModel 

                                                  ("http://gwserver.com:8000/sap/opu/odata/sap/Z_UI5_USER_MAINT_CM/");     

              sap.ui.getCore().setModel(oModel); 

 

use oModel update method

.update(sPath,oContext,oData,fnSuccess,fnError,bMerge);

 

where

* Trigger a PUT/MERGE request to the odata service that was specified in the model constructor.

* @param {String} sPath A string containing the path to the data that should be updated.

*                                                                       The path is concatenated to the sServiceUrl which was specified

*                                                                       in the model constructor.

* @param {Object} [oContext] If specified the sPath has to be is relative to the path given with the context.

* @param {object} oData data of the entry that should be updated.

* @param {function} [fnSuccess] a callback function which is called when the data has

*                                                               been successfully updated.

* @param {function} [fnError] a callback function which is called when the request failed. The handler can have the parameter: oError which contains

* additional error information.

* @param {Boolean} [bMerge=false] trigger a MERGE request instead of a PUT request to perform a differential update

 

 

   there is small problem in the document.

the parameter sequence mentioned in document is

   sPath,oContext,oData,fnSuccess,fnError,bMerge

 

but in the code it is

  sPath,oData,oContext,fnSuccess,fnError,bMerge

 

oModel.update('z_ui5_user_maintCollection('AGAMPA')',Odata);

 

________________________________________________________________________

 

if the XSRF token is disabled in SAP Gateway we have to pass the header X-Requested-With=XMLHttpRequest based on http://help.sap.com/saphelp_gateway20sp03/helpdata/en/e6/cae27d5e8d4996add4067280c8714e/frameset.htm

 

 

we can have add X-Requested-With in the Model

oModel.oHeaders["X-Requested-With"] = "XMLHttpRequest"

 

_______________________________________________________________________

 

 

Other  Operation

 

For Create

* Trigger a POST request to the odata service that was specified in the model constructor.

* @param {String} sPath A string containing the path to the collection where an entry

*                                                                       should be created. The path is concatenated to the sServiceUrl

*                                                    which was specified in the model constructor.

* @param {Object} [oContext] If specified the sPath has to be is relative to the path given with the context.

* @param {object} oData data of the entry that should be created.

* @param {function} [fnSuccess] a callback function which is called when the data has

*                                                               been successfully retrieved. The handler can have the

*                                       following parameters: oData and response.

* @param {function} [fnError] a callback function which is called when the request failed. The handler can have the parameter: oError which contains

 

.create(sPath,oContext,oData,fnSuccess,fnError)

 

 

For Batch

http://scn.sap.com/community/developer-center/front-end/blog/2012/11/18/gateway-batch-calls-from-sapui5

 

For Delete

* Trigger a DELETE request to the odata service that was specified in the model constructor.

* @param {String} sPath A string containing the path to the data that should

*                                                    be removed. The path is concatenated to the sServiceUrl

*                                                    which was specified in the model constructor.

* @param {Object} [oContext] If specified the sPath has to be is relative to the path given with the context.

* @param {function} [fnSuccess]  a callback function which is called when the data has

*                                                               been successfully retrieved. The handler can have the

*                                       following parameters: oData and response.

* @param {function} [fnError] a callback function which is called when the request failed. The handler can have the parameter: oError which contains

* additional error information.

 

.delete((sPath,oContext,fnSuccess,fnError))

 

 

Regards,

Jibin Joy

Essential Tools for Developers

$
0
0

Every developer no matter what their speciality has their favourite tools that allow them to work better, work faster or simply just because they like it. I have the pleasure of saying that I am no different. I thought it would be nice to jot down some of the tools that I love to use when sitting down with my coffee and headphones to experiment with the latest in development wizardry.

 

I want to start off by saying that this is by no means an exhaustive list of my favourite tools but rather the ones that come to mind for me the most. Please feel free to add your own suggestions below in fact I urge you to add more to this list because I love adding to my stock of brilliant utilities that enable me to do my job better J

 

SourceTree1_SourceTree.png

My first tool is source tree. I fall firmly into the GIT camp rather than the SVN camp and SourceTree is one of the best GIT clients that I have found out there. It is brilliantly simple to use and gives the best overview of the state of your source code compared with all of the other tools I have tried. It is free and cross platform too so this is one for both PC users as well as Mac users.

 

 

 

Sublime Text 22_Sublime.png

This one I cannot take credit for. Last year on the way back from TechEd Madrid I took the bus with DJ Adams and he suggested I try Sublime Text 2 as my text editor. I can honestly say that I have not looked back. It has an excellent and simple UI and can cater for the syntax of most programming languages as well as functioning really well as a distraction-less way of taking notes in meetings.

 

 

 

 

Fiddler 23_Fiddler.png

This is an interesting one, Fiddler 2 is a web traffic proxy which is great for debugging on your laptop. I have used this quite a bit while doing some performance analysis/tuning on some BPC 7.5 systems. It’s also good for monitoring traffic going in/out of your computer when trying to figure out if your web-apps are behaving themselves.

 

 

Caffeine4_Caffeine.png

I don’t mean a coffee but rather a really nifty application I use on my Mac. Are you ever in the middle of doing something and you stop to re-read or concentrate on something for a few minutes and in that time your screen saver starts? Well this little tool is excellent for preventing this. It sits in your tool bar at the top of your screen at all times, tap once to disable computer sleep, tap again to re-enable it – simple, really effective and best of all – free!

 

 

Eclipse5_Eclipse.png

This is a no-brainer. Eclipse is right up there as one of the best IDE’s out there. Not to mention that between the SAP Mobility Platform, SAPUI5, Hana Studio and Blackberry I spend quite a bit of my time in Eclipse these days. My only problem with Eclipse is the sheer number of Eclipse installations I have on my laptop but there are worse problems in the world to complain about.

 

 

 

Jenkins6_Jenkins.png

This is more one for a server than your laptop but still worth a mention I think. Automated testing is one of a number of powerful tools I would suggest for any project to bring peace of mind as well as speeding up your building and testing time. Jenkins is an excellent continuous integration server that is very configurable and well worth the time investment to get it up and running.

 

 

 


GIMP7_Gimp.png

GIMP is a great free image editor that rivals some commercial products like Photoshop and others. Inevitably during projects you end up wanting to adjust something slightly and paint just does not cut it. I use GIMP for those kind of minor changes and it works really well. It is cross platform and more recent releases have increased its usability quite a bit.

 

 

 

Dropbox/Google Drive or SkyDrive

These three I could not pick a favourite from – it’s great to have cross platform options to keep all your files in sync. I find a sync utility like one of these invaluable for keeping my files in sync across multiple OSs and laptops.

 

Coffee

This one is exactly what it says on the tin. Just plain old coffee. Strong in the morning, medium in the middle of the day and either strong again or decaf in the afternoon (depending on your deadlines!).

 

These are just a few of the many tools I use. My list of favourites changes pretty often as I continue my never-ending search for tools to aid my productivity or just to make my life easier.

What SAPUI5 and Fiori tells us about the future of UI development skills

$
0
0

At the recent SAPPHIRE event in Orlando, SAP unveiled a collection of impressive looking web apps named 'Fiori', built on SAP's new HTML5 framework (affectionally referred to as SAPUI5).  SAPUI5 (which is based on HTML/CSS/Javascript and built on libraries such as jQuery) has been in the making for over a year now.  But the release last week by SAP of Fiori apps has demonstrated that SAP is dead serious about SAPUI5 as a UI development toolkit going forward.

DJ Adams foresaw the shift to SAPUI5 over a year ago in this post.  Then, Bjoern Goerke mentioned it quite plainly in this recent blog post, when he says

SAPUI5, our HTML5 controls library, that SAP is using as the standard User Interface Control library in all their future applications that need a “consumer grade” User Experience

 

In fact, in SAP's own User Interface Technologies Roadmap 2013, SAPUI5 is considered a viable UI technology in any scenarios irrespective of levels of usage or reach (although clearly Fiori apps currently target the higher usage or reach scenarios).  If we assume then that once customers get a taste of Fiori apps, they will crave more over time, and expectations of "consumer grade" user experience will become more pervasive, what does that mean for the expectations of developer skills?

 

SAP gives us a hint with a table in the Appendix of the User Interfaces Roadmap 2013, where a comparison of Classic Dynpro, Web Dynpro ABAP, and SAPUI5 technologies is made.  Here is what we see ...

 

 

UI Technology
Skills Required (per SAP UI Roadmap)
Dynpro

ABAP & Dynpro

Web Dynpro ABAPABAP OO, Web Dynpro ABAP, Floorplan Manager
SAPUI5Javascript, HTML5, CSS3, Gateway, OData

 

 

If you look closely, this is a big shift in skill expectations for SAP developers, not unlike a decade ago when SAP sought to shift the user interface layer onto the Java stack.  With SAPUI5, web developers are expected to craft the client-side web application with HTML5/CSS/Javascript, whilst ABAP developers focus on the business logic in the ABAP system, exposed as APIs using NetWeaver Gateway and consumed by the web application.  To illustrate further, SAP's guide to extending or enhancing Fiori apps which are based on SAPUI5 provides the following table ...

 

SAPUI5 skills.png

 

 

 

With this shift to SAPUI5 over time, I foresee some challenges in the SAP ecosystem ...

 

 

Can SAP rely on the ABAP development community to upskill to SAPUI5?

My opinion here, is that not enough numbers will make the shift.  That's based on my observations in the field.  Many developers are still not comfortable with the shift to Web Dynpro ABAP .... indeed, this was evidenced at a TechEd I attended 18 months ago when the first booked-out hands-on session was 'Introduction to Web Dynpro ABAP'.  So if many ABAP developers have struggled to make the leap to Web Dynpro ABAP (and associated concepts such as FPM and ABAP OO), I'm not hopeful that a large proportion will be able to upskill with Javascript, HTML5 etc.  That said, ABAP developers will still be needed to craft the underlying business logic under Gateway services.  This does raise the spectre of multi-developer scenarios to achieve anything with SAPUI5 - A front-end developer for the web app, and a back-end developer for the business logic.  This is something which customers needed to contend with in the Web Dynpro Java days when business logic was still embodied in ABAP, so you needed a Web Dynpro Java developer to craft the front-end user interface, and an ABAP developer to refine the business logic in ABAP function modules.  It will be interesting to see if customers are willing to embrace that multi-developer scenario again.  That said, this split between front-end developers and back-end developers is not unusual in some worlds.  And of course, those few who have the skills for both tiers will be highly in demand.

 

 

Can SAP engage a new community of web developers to embrace SAPUI5, outside the traditional SAP ecosystem?

I would certainly like to see this, although I think much more could be done.  I am fearful that SAP in it's desire to craft a proprietary HTML5 framework in SAPUI5 may choke opportunities for it to see mass adoption.  I look back to Web Dynpro Java, another proprietary framework, and how I think that most pure Java developers that you meet on the street have not heard of it - that's not mass adoption.  Licensing of SAPUI5 usage is also problematic.  My understanding (currently) is that whilst SAPUI5 is free to trial, productive use requires a SAP development license (eg. NetWeaver development license or SAP HANA Cloud).  That's enough to turn most non-SAP web developers away - these web developers tend to use free open source or low cost frameworks.  Also the licensing implies usage is pretty much restricted to SAP platform scenarios (somewhat like Web Dynpro Java).  Most web developers walking into a SAP usage scenario will instead prefer to use more commonly known libraries or frameworks - ones that they have hands-on experience and expertise with, and are freely available and/or open sourced, such as Twitter Bootstrap. Personally I think SAP could do more to make SAPUI5 more visible, perhaps making it open-source, and also increasing promotion of it outside the traditional SAP TechEd conferences - I've attended some developer and web developer conferences in Australia recently and lamented that there was no presence or sponsorship by SAP at those events.  Right now, there is a fierce battle underway in the web ecosystem around what web frameworks or libraries web developers choose to adopt (eg. all the various Javascript MV* frameworks) - in my mind those with sufficient adoption will be more likely to succeed or have greater longevity.  And for many web developers, SAPUI5 isn't on their radar.

 

 

 

SAP's software engineering teams have crafted a nice framework for SAP's user interface future.  But I'm wondering if we are heading for a skills sinkhole around SAPUI5, where inadequate numbers of traditional SAP developers move into this space, and non-SAP developers remain unengaged due to lack of visibility and licensing concerns.  I'm hoping I'm wrong.

Fortgeschrittene Javascript-Programmierung: Objekte und Closures

$
0
0

 

Javascript als Grundlage moderner Webtechnologien

 

Einleitung

 

Im Wandel der Zeit

 

Schon seit längerem ist zu beobachten, dass der Browser mehr und mehr zur wichtigsten Plattform zur Ausführung von Anwendungen avanciert. Nicht zuletzt hat HTML5 diese Entwicklung deutlich unterstrichen. Mit dem neuen Standard können Anwendungsentwickler auf eine Vielzahl von Funktionen zurückgreifen, die bisher nur klassischen Desktop-Applikationen vorbehalten waren. Auch SAP hat diesen Trend erkannt und mit SAPUI5 ein Framework auf den Markt gebracht, welches die Vorteile des neuen HTML-Standards in die SAP-Anwendungsentwicklung übertragen soll.

 

Neue Anforderungen an Entwickler

 

Wer mit SAPUI5 arbeiten will, muss gut mit Javascript umgehen können. Keine einfache Aufgabe für gestandene ABAP- und Java-Programmierer, denen die Eigenheiten von Javascript auf den ersten Blick sehr gewöhnungsbedürftig anmuten müssen. Zugegeben, anfangs erfordert es etwas Mut, um nicht zu sagen Überwindung, sich auf eine dynamisch typisierte, interpretierte Skriptsprache einzulassen. Wer den Sprung ins kalte Wasser jedoch überstanden hat, wird vielleicht mit keiner anderen Programmiersprache mehr arbeiten wollen. Denn Javascript bieten gerade in der Entwicklung der Präsentationslogik unglaublich viele Vorteile gegenüber ABAP und Java. Wie sich das genau ausdrückt, wollen wir uns im Folgenden etwas genauer ansehen. Ziel sollte es sein, eine eigene SAPUI5-App strukturell sauber und wartbar entwickeln zu können.

 

Von globalen Funktionen zu Closures

 

Schritt 1: Globale Funktionen und Variablen

 

In viele Webanwendungen wird ausschließlich mit global deklarierten Variablen und Funktionen gearbeitet. Folgendes Coding könnte entweder in einer eigenen .js -Datei oder in eine <script>-Bereich der HTML-Seite abgelegt sein.


var a = 1;

function b(){
   alert(a);
}

b();

 

Auf diese Weise ist sowohl Variable a als auch Funktion b von globaler Sichtbarkeit. Je umfangreicher das Coding wird, desto schwieriger wird es für den Anwendungsentwickler die Übersicht zu behalten. In objektorientierten Sprachen existiert zu Lösung dieser Problems die Klasse, welches logisches und konzeptionell zusammengehöriges Coding kapselt. ABAP und Java bieten genau dieses Feature an, weshalb man hier von klassenbasierter Objektorientierung spricht. In Javascript gibt es keine Klasse, welche sozusagen als Schema für Objekterzeugung verwendet werden könnte. Stattdessen vertraut man hier auf die prototypenbasierte Objektorientierung, sodass Objekte aus anderen Objekten (den sog. Prototypen) erzeugt werden. Um genau das zu tun, gibt es unterschiedliche Vorgehensweisen.

 

Schritt 2: Objekte als Namespaces

 

Wie wir gleich sehen werden, überführen wir das Coding aus Schritt 1 in einen etwas übersichtlicher Ansatz.

 

var myScope = myScope || {};

myScope.a = 1;

myScope.b = function(){
   alert(myScope.a);
}

myScope.b();

 

Zunächst erzeugen wir ein Javascript-Objekt. Falls das Objekt jedoch schon existieren sollte, weisen wir die bestehende Instanz zu. Falls "myScope" initial sein sollte, wird durch die geschweifte Klammern ein neues Objekt erzeugt. Danach erfolgt die Deklaration einer Eigenschaft und einer Methode auf Basis des Objektes. Methode b ist somit nicht mehr global sichtbar, sondern nur über das Objekt "myScope" erreichbar.

Es wird ersichtlich, dass Objekte als einfaches Mittel zur Strukturierung des Codings eingesetzt werden können. Auf diese Weise können nun logisch zusammengehörige Funktionen in gleiche Namespaces abgelegt werden. Allerdings erlaubt uns dieser Ansatz noch keine klassische Objekterzeugung im eigentlichen Sinne (sprich: aus Schema wird konkrete Instanz).

 

Schritt 3: Funktionskonstruktoren

 

Hier sehen wir nun die Definition eines Funktionskonstruktors, über welchen wir mit dem Schlüsselwortnewneue Instanzen erzeugen können.

 

function MyObject(a, b, c){    this.a= a;   this.b= b;   this.c= c;   this.toString = function(){      return this.a+" "+this.b+" "+this.c;   };
}

var myObject = new MyObject(1,2,3);

myObject.toString();

 

Rein theoretisch könnte man für alle fachlichen Entitäten (z.B.: Person, Rechnung etc.) solche Konstrukte erzeugen und die Logik als Funktionen analog zur obigen toString-Funktion implementieren. Wer auf eine etwas kompaktere, JSON-lastigere Syntax steht, kann auch folgenden Ansatz wählen.

 

function MyObject(a, b, c){   return  {      a: a,      b: b,      c: c,      toString  : function(){         return this.a+" "+this.b+" "+this.c;      }   };
}
var myObject = new MyObject(1,2,3);

myObject.toString();

 

Das Ergebnis der Objekterzeugung ist identisch zum vorigen Listing.

 

Schritt 4: Nutzung von prototype

 

Die akademisch korrekte Erweiterung von Javascript-Objekten zur Laufzeit wird über die prototype-Anweisung abgebildet. Ausgangssituation ist wiederum ein leeres Objekt, welches wir dynamisch über weitere Funktionen erweitern wollen.

 

var MyObject = function(){};

MyObject.prototype.constructor = MyObject;

MyObject.prototype.a = 1;

MyObject.prototype.b = function(){
   alert(this.a);
}

// Objekterzeugung
var myObject = new MyObject();

myObject.b();

// Objekt-Erweiterung zur Laufzeit
MyObject.prototype.c = 5;

alert(myObject.c);

 

Über die formale Definition eines Konstruktor und die Erzeugung eines leeren Objektes über die function Anweisung, können wir nun beliebig Gebrauch von dynamischen Erweiterung mittels prototype Gebrauch machen. Eine Erzeugung eines Objektes über {} hätte an dieser Stelle nicht ausgereicht. Im Folgende das gleiche Coding, nur etwas kompakter

 

var MyObject = function(){};

// JSON-Syntax
MyObject.prototype = {
   constructor : MyObject,   a : 1,   b : function(){      alert(this.a);   }
}

// Objekterzeugung, wie oben
var myObject = new MyObject();

myObject.b();

MyObject.prototype.c = 5;

alert(myObject.c);

 

 

Schritt 5: Closures

 

Nun sind wir zwar in der Lage, eine dynamsiche Objekterzeugung vorzunehmen, allerdings fehlt uns zur besseren Strukturierung des Codings die Möglichkeit, öffentliche und private Schnittstellen zu definieren. Wir benötigen ein Konzept zur Eingrenzung von Sichtbarkeitsbereichen, ohne auf Schlüsselworte wie public und private zurückgreifen zu müssen (die es in Javascript ohnehin nicht gibt^^). Um dies zu erreichen, implementieren wir ein Closure bzw. eine sich selbst ausführende, anonyme Funktion.


(function(){  // Neuer Sichtbarkeitsbereich
}());

 

Zugegeben, auf den ersten Blick sieht dieses Konstrukt etwas seltsam aus. Aber im Prinzip ist es nichts anders als eine anonyme Funktion, welche nach ihrer Definition durch () sofort aufgerufen wird. Der gesamte Block wird dann nochmal von zwei Klammern umfasst und endet mit einem Semikolon. Im nächsten Listing wollen wir die anonyme Funktion mit ein paar Parametern versorgen.

 

(function(MYAPI, $, undefined){

}(window.MYAPI = window.MYAPI || {}, jQuery));

 

Der erste Parameter ist window.MYAPI = window.MYAPI || {}. Wir übergeben hiermit einen Namespace bzw. erzeugen in mit {}, falls er noch nicht existieren sollte. Falls wir jQuery verwenden (ist bei SAPUI5 ja der Fall) übergeben wir als zweiten Parameter das jQuery Objekt. Das hat den Hintergrund, dass wir im eigentlichen Closure das $ nicht neu definieren wollen. Gleiches gilt für das undefined-Schlüsselwort. Im Internet hat sich dieser best-practise zum Schutz vor Redifinition in den letzten Jahren durchgesetzt. Nun wollen wir den neuen Sichtbarkeitsbereich für unsere Zwecke nutzen.

 

(function(MYAPI, $, undefined){   // "privates" Attribut, nur innerhalb des Closures sichtbar   var test = "It works!";   // "private" Funktion   function createPopup(){      alert(test);   }   // Definition eines neuen Namespaces   MYAPI.PERSON= function(){};   // Öffentliche Methode über den Namespace MYAPI.NEWSCOPE   MYAPI.PERSON.prototype.doSomething = function(){      createPopup();   };
}(window.MYAPI = window.MYAPI || {}, jQuery));

// Außerhalb des Closures kann nur über den Namespace ein Aufruf stattfinden
var person = new MYAPI.PERSON();
person.doSomething();

 

Mittels dieses Programmierparadigmas lassen sich zusätzliche Sichtbarkeitsbereiche schaffen. Außerdem kann das Coding modular aufgebaut werden. Für jedes Modul bzw. für jede Komponente wird ein Closure definiert und in einer eigenen .js-Datei abgelegt. In einer index.html führen wir dann alle .js-Dateien zusammen. Eine weitere typische Eigenschaft des Closures besteht darin, dass alle "privaten" Variablen selbst nach Verlassen der anonymen Funktion nicht initialisiert werden (im obigen Beispiel würde Variable "test" seinen Wert beim Verlassen der Funktion nicht verlieren). Mit anderen Worten werden die Werte nicht aus dem Speicher gelöscht, sondern bleiben für die Dauer der Programmausführung erhalten.

 

Idealerweise kombiniert man Closures und Funktionskonstruktoren, um in den Genuss maximaler Kapselung zu kommen. Unter folgendem Link kann obiges Listing bei js-Fiddle getestet werden.

 

Fazit

 

Mit Hilfe dieser Ansätze lassen sich auch komplexe Anforderungen übersichtlich in Javascript realisieren. Egal ob man nun mit SAPUI5 oder einem anderen Framework arbeitet, die hier gezeigten Techniken lassen sich immer beim Arbeiten mit Javascript anwenden.

How to create SAPUI5 application consuming Gateway service with the help of SAP NW Gateway Plug-in for Eclipse

$
0
0

Introduction -

 

In this technical blog, I will focus on how we can build SAPUI5 application consuming GW service with the help of SAP NetWeaver Gateway plug-in for Eclipse.

 

SAP NetWeaver Gateway plug-in for Eclipse -

The SAP NetWeaver Gateway plug-in for Eclipse is an SDK that enables the developer to easily and quickly create applications that consume data from SAP systems via OData services exposed by SAP NetWeaver Gateway

The framework enables developers using Eclipse to do the following:

  • Discover, explore and search SAP services in SAP NetWeaver Gateway
  • Generate semantic proxies for SAP services
  • Leverages templates for generating starter applications based on SAP services.


Prerequisites –

You should have Eclipse IDE with SAP UI development toolkit for HTML5 and access to SAP NetWeaver Gateway system.

You should also need to install SAP NetWeaver Gateway plug-in for Eclipse which can be downloaded at

http://www.sdn.sap.com/irj/scn/downloads?rid=/webcontent/uuid/b09d414f-f227-2f10-bdbf-ba31c844b432

Procedure -

Steps involved for creating simple UI5 application consuming Gateway services with the help of Gateway plugin for Eclipse are as below,

 

  1. Select Starter Application Project as displayed in below screenshot ui5_gw1.jpg
  2. Give project name and select HTML5

ui5_gw2.jpg

   3. Select List/Details Application (SAPUI5) 

ui5_gw3.jpg

   4. In this step, we want to select Gateway service either from remote location or from File system. We will choose Remote location and connect to SAP Gateway system

ui5_gw4.jpg


   5. Here we can configure connection to SAP NW GW system

 

ui5_gw5.jpg

  6. Do not select checkboxUse HTTPS. Provide server host name and server port. Provide user credentials and select checkboxSave Passwordand click on OK.

 

ui5_gw6.jpg


   7. If you are able to connect to Gateway system then you will be able to see list of all gateway services available in your SAP system. And you can search for services.

ui5_gw7.jpg


   8. Here, we will start searching standard GW service SAMPLEFLIGHT

ui5_gw8.jpg

   9. Select service SAMPLEFLIGHT. This service contains 4 entity set such as BookingCollection, CarrierCollection, FlightCollection and TravelagencyCollection.  Entity Set can be considered as internal table.

 

ui5_gw9.jpg

   10. Click on Next

ui5_gw10.jpg

   11. Now we can create view of type List for Entity Sets. We will choose Entity Set FlightCollection.

ui5_gw11.jpg

   12. Click on + sign to add fields to the view

 

ui5_gw12.jpg

  13. As displayed below, Click on Finish and UI5 application will get generated.

ui5_gw13.jpg

 

Below snap gives details on final project structure generated automatically by the wizard.

ui5_gw14.jpg

  14. We can start testing the application by Run As a Web App Preview

 

ui5_gw15.jpg

This will open index.html page with URL. As displayed below, this page does not display any information. Now we would like to see what errors occurred.

 

 

ui5_gw16.jpg

 

To troubleshoot, we can use Chrome browser as it comes up with inbuilt tools as shown below.

ui5_gw17.jpg

By pasting the URL in chrome browser and activating developer tools, we will be able to see errors on console. As per below error, /sapui5-1.4 is not loaded.

 

ui5_gw18.jpg

 

For this, we need to modify the bootstrap scrip in index.html page

 

ui5_gw19.jpg

 

 

It should be,

src="resources/sap-ui-core.js"

After correcting this error, we can reload URL and see the results. Now it is displaying Flight table but with no data and there are errors related to unauthorized access to Gateway service ,i18n_en_US file not found as well as Origin localhost is not allowed by Access-Control-Allow-Origin.

ui5_gw20.jpg

 

To correct these errors, in web.xml file, we need to add <context-param> tags with < param-value> pointing to SAP Gateway system server host and port.

<!-- ============================================================== -->

<!-- UI5 proxy servlet -->

<!-- ============================================================== -->

<servlet>

<servlet-name>SimpleProxyServlet</servlet-name>

<servlet-class>com.sap.ui5.proxy.SimpleProxyServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>SimpleProxyServlet</servlet-name>

<url-pattern>/proxy/*</url-pattern>

</servlet-mapping>

<context-param>

<param-name>com.sap.ui5.proxy.REMOTE_LOCATION</param-name>

<!-- <param-value><host>:<port></param-value> -->

<param-value>http://hostname.com</param-value>

</context-param>

Also add below code to index.html

This will add proxy to your URL when we are testing the application locally.

 

ui5_gw21.jpg

 

 

 

To remove error related to i18n, copy file i18n.propeties and paste under globalization folder and rename it to i18n_en_US.properties. This should remove error.

 

ui5_gw22.jpg

 

Apart from these changes, in controller JS file, we need to add “/” before the entity set name else you will get Bad call error message.

Hence it should be oTable.bindRows(“/FlighCollection”);

 

ui5_gw23.jpg

 

 

 

Once all these required changes are done in the generated code, you can reload the URL which will display the output as below,

Output -

ui5_gw24.jpg

 

Closing Remarks –

With the help of SAP Gateway Plugin for Eclipse, we can create starter SAPUI5 application with very minimum efforts.

This step-by-step blog is written to explain how we can,

 

1)     Configure SAP NW GW system,

2)     Search existing gateway services

3)     Create UI5 application consuming gateway service 

4)     Troubleshoot issues with the help of developer tool available in Google chrome browser

5)     And test the application locally

 

Though we can create very basic application using this plugin,it will help us to understand/learn UI5 application structure and gateway service basics.

Additional Information –

In this blog, I am using our local SAP NetWeaver Gateway system. In case, if you do not have access to Gateway system then you can use SAP NetWeaver Gateway Demo System hosted by SAP.

you need to use below credentials,

Username: GW@ESW

Password: ESW4GW

 

Before starting building application, you may want to check if the system is up and running. to test it, try to access below URL and provide above credentials,

 

http://gw.esworkplace.sap.com/sap/opu/sdata/iwfnd/SAMPLEFLIGHT/$metadata

 

if the demo system is up and running, you will see below output

 

ui5_gw25.jpg

 

Now, we will try to see if there is data available for entity set CarrierCollection. For that, put below URL in the chrome browser,

http://gw.esworkplace.sap.com/sap/opu/sdata/iwfnd/SAMPLEFLIGHT/CarrierCollection

 

you may get output as below,

ui5_gw26.jpg

After confirming that we are getting data from SAMPLEFLIGHT oData service, we will configure connection to demo system as below,

ui5_gw27.jpg

We need to add parameter for REMOTE_LOCATION with host as demo system,

ui5_gw28.jpg

connectivity.js will look as below,

ui5_gw29.jpg

and "/" before CarrierCollection in your_view_name.controller.js so that it will be as below

oTable.bindRows("/CarrierCollection");

 

That's it !!

Now try to run application and paste the URL into chrome browser, it will display pop up for authentication. Provide credentials as mentioned above.

If everything is fine, you will be able to see output.

 

 


How to install a basic development environment for SAPUI5

$
0
0

It's all about Java

 

I want to show you, how you create your own development environment for SAPUI5. You will see, that we are going to use some great tools, which are normally known from Java-Development. I will use Windows 7 as operating system.

 

Step 1: Install Java Development Kit (JDK)

 

The JDK is the Java package for developers. which includes a complete Java Runtime plus tools for developing, debugging, and monitoring Java applications. You can download the latest version from this site. After the download has finished, run the installer.

 

Step 2: Set Up Environment Variables

 

After the installation of your JDK, it's important to create a new environment variable called JAVA_HOME. To do this, open your "Run" window in Windows and type in "control sysdm.cpl". On the Advanced tab, click Environment Variables. Then create a new System variable called JAVA_HOME. The value of this should be the path to your JDK.

 

ev.png

After that, you have to add this variable to the existing PATH-Variable with %JAVA_HOME%;

path.png

Finally, when you open your command prompt, following command should work. "java -version"

cmd.png

This basic configuration is very important for Java-tools like your web server. To check your environment variables quickly, you can open your console and run the "SET" command, which displays all environment variables of your system.

 

Step 3: Install Eclipse

 

Go to this site and download the latest version of Eclipse IDE for Java EE Developers. Extract the zip-file to a directory of your choice (for example "C:\Program Files\eclipse"). When you start eclipse, you have to choose a workspace. This is a specific folder, where eclipse stores your projects.

 

Step 4: Install a Java Web Server

 

You will need a Java Web Server (also known as Servlet-Container), when you want to deploy and run your applications. I recommend the Apache Tomcat, but the Jetty Server for example is also a good option. Download the current tomcat from the download section of the official site. Extract all files in a directory, for example "C:\Program Files\apache tomcat". To test your configurations, go to the "bin" folder and try to run the startup batchfile to start server-mode. When everything is find, you should see a window like this:

 

tomcat.png

If your server has problems to start, you should check your environment variables (especially JAVA_HOME and PATH) and your java installation. You can shutdown your server with the "shutdown" batchfile.

 

Step 5: Add Web Server to Eclipse

 

If you want to deploy applications directly from your eclipse, you have create a new server instance in your IDE. Open Eclipse, go to "File - New - Others" and choose "Server". In the next window, choose Apache Tomcat (with correct version) as server type and type in following information:

 

server.png

After that, click finish. When you now open your Server-View ("Window - Show View - Server"), you should see your new instance. When you right-click on this entry, you can easily start and stop your server and do some configuration stuff.

server_view.png

 

Step 6: Install SAPUI5 Plugin

 

First, download the evaluation package from scn. After download, extract everything. Now go to your eclipse under "Help - Install New Software...". Click "Add" and in the following window "Local...". Navigate to your directory, where you extracted your evaluation package. Choose the directory "tools-updatesite". When everything works, you should see the following:

plugin.png

Select the entry "UI development toolkit for HTML5" and press finish. The remaining part of the installation should be no problem. Restart eclipse after you complete the installation. Then go to "File - New - Others" and type in the Wizard "SAP". You should see this (sry, for the german text):

project.png

When you choose "Application Project" and complete the wizard, you should have a basic SAPUI5-project and some initial files in your eclipse. The following picture shows the entry in the project explorer. If your project isn't displayed correctly in this view, you maybe have to change the "perspective" under "Window - Open Perspective - Java EE".

 

project_explorer.png

 

Step 7: Run your Project

 

Go to your new project and open in the directory "WebContent" the index.html. Then, click on the Run-Button:

run.png

In the following window, choose "Run on Server" and press "OK". The next window shows a listing of all available servers in your eclipse. In this case, we choose our tomcat server and activate the checkbox at the bottom. Click on finish.

start.png

 

You will see, that your web server will start and an the index.html will shown in an preview window. Congratulation! Now you can start to develop your application and test it on your local machine.

 

Some useful hints

 

1. Deployment and Tomcat Server Mode

 

When you want to present your application or run it in production, you can deploy your SAPUI5 app very easily on the tomcat server. When you don't use a build tool like ANT or MAVEN you have to export your project out of eclipse manually. Right-click on your project, choose "Export - War File". Provide the following form with some information like this:

 

war.png

After that, copy the war-File in the "webapps" directory of your apache tomcat. After a Restart (run "startup.bat"), you can now access your app under http://localhost:8080/<your_app>/.

 

2. Browsers

 

In SAP-Development, most projects are running on Internet Explorer. But for SAPUI5 - development, it's much better to use Chrome or Firefox(with firebug plugin), because both systems offer a great set of tools and plugins to debug your JavaScript, inspect your HTML, CSS and network activities and a lot of more cool stuff. Because Chrome is my favorite, you should have look at this site, where all details are explained perfectly.

 

I hope, all this information help you to get started with SAPUI5.

 

ENJOY!!!!


SAPUI5 technical support question

$
0
0

The specific problem from one of our colleagues – Jeremy Morris  jeremy.morris@accenture.com–he is having an issue in passing data from a list view in a page defined by JavaScript to a page showing a detail view of the list item selected. The detail view fails to get hold of the data it needs to display the detail view.  There is an attached example which is very similar to the SAPUI5 SDK example called MVC. It uses the same data file (countries.json). The only difference is that my example defines all views using JavaScript whereas the demo code defines some views using XML. The demo code works whereas the example code does not - how could we share the project in ZIP file?

SAP and mobile powers combined through SAPUI5 and PhoneGap

$
0
0

Last year Dagfinn Parnas wrote an article about combining SAPUI5 and PhoneGap:

Building awesome mobile apps with SAPUI5 and PhoneGap

 

Dagfinn Parnas didn't use the SAPUI5 mobile library so the full power of combining SAPUI5 and PhoneGap wasn't achieved. I haven't found anyone else on the internet make this possible either. With this blog post I will demonstrate how you can combine SAPUI5 mobile library with PhoneGap. This will make it possible for you to build native apps for all mobile platforms. You can use eclipse if you want but I will demonstrate the process without it for you, so that you will understand it deeper.

 

All the below files are available at my GitHub:

https://github.com/morganap/SAPUI5andPhonegap

 

Step 1:

Download SAPUI5: http://scn.sap.com/community/developer-center/front-end

Unzip the downloaded file.

 

Step 2:

In the SAPUI5 folder delete the following to reduce its size:

 

From sapui5-static.zip, delete:

           /test-resources/*

           /discovery/*

           /resources/sap-ui5-dbg.js

           /resources/sap-ui-core-all-dbg.js

           /resources/sap/uiext/*

           /resources/sap/service/*

           /resources/sap/makit

           /resources/sap/viz chart libraries

 

and in /resources/sap/ui/ the following library folders

           commons

           qunit

           richtexteditor

           table

           test

           ux3

 

The instruction above is from Andreas Kunz: http://scn.sap.com/thread/3287821

 

Step 3:

In the SAPUI5 folder you copy the resources folder to a place where you want to develop the web app.

(If you already have SAPUI5 version 1.10.4 and want to retrieve the resource folder check my other article

"SAP and mobile powers combined through SAPUI5 and Phonegap - make it work with new SAPUI5 version")

And then create an index.html file and a config.xml file like the picture below:

 

 

In the index.html file insert the code bellow:

 

Filename: index.html

<!DOCTYPE HTML>

<html>

       <head>

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

 

 

                    <script src="phonegap.js"></script>

              <script type="text/javascript" charset="utf-8">

 

 

                        var pictureSource;   // picture source

                        var destinationType; // sets the format of returned value

 

                        // Wait for Cordova to connect with the device

                        //

                        document.addEventListener("deviceready",onDeviceReady,false);

 

                        // Cordova is ready to be used!

                        //

                        function onDeviceReady() {

                            pictureSource=navigator.camera.PictureSourceType;

                            destinationType=navigator.camera.DestinationType;

                            navigator.geolocation.getCurrentPosition(onSuccess, onError, {enableHighAccuracy:true});

                        }

 

                        // Called when a photo is successfully retrieved

                        //

                        function onPhotoDataSuccess(imageData) {

                          // Uncomment to view the base64 encoded image data

                          // console.log(imageData);

 

                          // Get image handle

                          //

                          var smallImage = document.getElementById('smallImage');

 

                          // Unhide image elements

                          //

                          smallImage.style.display = 'block';

 

                          // Show the captured photo

                          // The inline CSS rules are used to resize the image

                          //

                          smallImage.src = "data:image/jpeg;base64," + imageData;

                        }

 

                        // Called when a photo is successfully retrieved

                        //

                        function onPhotoURISuccess(imageURI) {

                          // Uncomment to view the image file URI

                          // console.log(imageURI);

 

                          // Get image handle

                          //

                          var largeImage = document.getElementById('largeImage');

 

                          // Unhide image elements

                          //

                          largeImage.style.display = 'block';

 

                          // Show the captured photo

                          // The inline CSS rules are used to resize the image

                          //

                          largeImage.src = imageURI;

                        }

 

                        // A button will call this function

                        //

                        function capturePhoto() {

                          // Take picture using device camera and retrieve image as base64-encoded string

                            navigator.camera.getPicture(onPhotoDataSuccess, onFail, { quality: 50,

                            destinationType: destinationType.DATA_URL });

                        }

 

                        // A button will call this function

                        //

                        function capturePhotoEdit() {

                          // Take picture using device camera, allow edit, and retrieve image as base64-encoded string

                          navigator.camera.getPicture(onPhotoDataSuccess, onFail, { quality: 20, allowEdit: true,

                            destinationType: destinationType.DATA_URL });

                        }

 

                        // A button will call this function

                        //

                        function getPhoto(source) {

                          // Retrieve image file location from specified source

                          navigator.camera.getPicture(onPhotoURISuccess, onFail, { quality: 50,

                            destinationType: destinationType.FILE_URI,

                            sourceType: source });

                        }

 

                        // Called if something bad happens.

                        //

                        function onFail(message) {

                          alert('Failed because: ' + message);

                        }

 

                     // onSuccess Geolocation

                        //

                        function onSuccess(position) {

                            var element = document.getElementById('geolocation');

                            element.innerHTML = 'Latitude: '           + position.coords.latitude              + '<br />' +

                                                'Longitude: '          + position.coords.longitude             + '<br />' +

                                                'Altitude: '           + position.coords.altitude              + '<br />' +

                                                'Accuracy: '           + position.coords.accuracy              + '<br />' +

                                                'Altitude Accuracy: '  + position.coords.altitudeAccuracy      + '<br />' +

                                                'Heading: '            + position.coords.heading               + '<br />' +

                                                'Speed: '              + position.coords.speed                 + '<br />' +

                                                'Timestamp: '          +                                   position.timestamp          + '<br />';

                        }

 

                        // onError Callback receives a PositionError object

                        //

                        function onError(error) {

                            alert('code: '    + error.code    + '\n' +

                                    'message: ' + error.message + '\n');

                        }

                    </script>

                    <script src="resources/sap-ui-core.js"

                                          id="sap-ui-bootstrap"

                                          data-sap-ui-libs="sap.m"

                                          data-sap-ui-theme="sap_mvi" >

                    </script>

                    <script>

                          // create a mobile App

                          // it initializes the HTML page for mobile use and provides animated page handling

                          var app = new sap.m.App("myApp", {initialPage:"page1"}); // page1 should be displayed first

 

                          // create the first page of your application

                          var page1 = new sap.m.Page("page1", {

                              title: "SAPUI5 and Phonegap",

                              content : [new sap.m.Text({text:"Hello Mobile World!"}),

                                         new sap.m.Button({   // content is just one Button

                                             text : "Go to next page",

                                             tap : function() {

                                                 app.to("page2", "fade");   // when tapped, it triggers drilldown to page 2

                                             }

                                             }),

                                             new sap.m.Button("open_camera_button", {

                                                      text : "Open camera",

                                                      tap : function () {

                                                                 capturePhoto();

                                                      }

                                             }),

                                             new sap.ui.core.HTML({content:'<p id="geolocation">Finding geolocation...</p> <img style="display:none;width:60px;height:60px;" id="smallImage" src="" /><img style="display:none;" id="largeImage" src="" />'})

                                                                      ]}

                          );

 

                          page1.setBackgroundDesign("List");

 

                          // create the second page of your application

                          var page2 = new sap.m.Page("page2", {

                              title: "Page 2",

                              showNavButton: true,       // page 2 should display a back button

                              navButtonTap: function(){

                                  app.back();            // when tapped, the back button should navigate back up to page 1

                              },

                              content : new sap.m.Text({text:"Hello Mobile World!"})

                          });

 

                          app.addPage(page1).addPage(page2); // add both pages to the App

 

                          app.placeAt("content"); // place the App into the HTML document

                    </script>

          </head>

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

                       <div id="content"></div>

    </body>

</html>

 

Step 4

Insert the following code in the config.xml file:

 

Filename: config.xml

<?xml version   ="1.0" encoding="UTF-8" ?>

<widget xmlns   = "http://www.w3.org/ns/widgets"

                xmlns:gap   = "http://phonegap.com/ns/1.0"

                id                      = "com.intel.sample"

                versioncode = "1"

                version                 = "1.0.0">

 

 

                <name>SAPUI5 and Phonegap</name>

 

 

                <content src="index.html"/>

 

 

                <description>

                    Test application with SAPUI5 and Phonegap

                </description>

 

 

                <preference name="phonegap-version" value="2.0.0" />

                <feature name="http://api.phonegap.com/1.0/camera"/>

                <feature name="http://api.phonegap.com/1.0/file"/>

                <feature name="http://api.phonegap.com/1.0/geolocation"/>

 

 

                      <!-- for iPhone -->

                      <plugin name="Camera" value="CDVCamera" />

                      <plugin name="Geolocation" value="CDVLocation" />

 

 

                <!-- for Android -->

                <plugin name="Camera" value="org.apache.cordova.CameraLauncher"/>

                <plugin name="Geolocation" value="org.apache.cordova.GeoBroker" />

                <preference name="orientation" value="portrait" />

                <preference name="android-minSdkVersion" value="9" />

</widget>

 

Step 5

Make your files to a zip file:

 

------------------------------------------------------------------------------------------------------------------------------------

 

 

------------------------------------------------------------------------------------------------------------------------------------

 

 

Step 6

Create a free account at:

https://build.phonegap.com

This web service makes it possible to build native apps to all different mobile platforms without needing to setup different native SDK environment for every mobile platform.

 

 

Step 7

Log in with your new account:

https://build.phonegap.com

Create a new app by pressing the new app button. Then choose private, like the below picture.

 

Upload your index.zip file that you created in step 5.

 

 

Step 8

When the upload is complete this app will appear. Press the "Ready to build" button.

 

 

Now wait for the build to complete for all the different mobile platforms.

 

 

Step 9

The build will succeed for every platform except iOS and blackberry. If you want to create iOS apps you will need to enter a developer code. It will require you to have an apple computer, iPhone and an apple developer account. Blackberry complains because it thinks there are too many files uploaded. This can sure be fixed and if anyone will give it a try I appreciate it.

 

 

Press the android figure above and a download of the apk file for that platform will begin. You can download the platform you want but I will describe below for the android platform. Send the downloaded file to your android phone. You can for example email it. Before opening the file you need to allow unknown sources in your phone:

 

For android 4 devices and up:

  1. Tap Menu.
  2. Tap Security.
  3. Check the box labeled Unknown Sources.

For older android devices:

  1. Tap Menu.
  2. Tap Settings.
  3. Tap Applications.
  4. Check the box labeled Unknown Sources.

 

Step 10

Now open your apk file in your android mobile device. This will give you an option to install it. Choose to install.

 

Step 11

Open your newly created application. Play around with the app! You can test to press the camera button.

 

 

The camera opens and you take a picture. Then the picture is placed under the Timestamp text:

 

 

Step 12

The above steps show how easy it is to develop apps for all mobile platforms using SAPUI5 and PhoneGap. So what are you waiting for! Give it a try!

Unleash the power of SAP and mobiles combined!

Useful jQuery Functions for SAPUI5 Development

$
0
0

jQuery: write less, do more.

 

jQuery is an amazing framework and part of SAPUI5. I want to show you some features, which could be very useful for your SAPUI5-App. You can try out each code snippet on jsfiddle.net. The complete documentation of all jQuery-functions is available right here.

 

Simple cross-domain Ajax request

 

This code shows, how you can call a web service from a different domain, without getting security issues (same origin policy). This call will only work, if your service supports JSONP.

 

// service url
var url = 'http://ip.jsontest.com/?callback=processJSON';

$.ajax({
    url: url,    jsonpCallback: 'processJSON',    dataType: 'jsonp',    success: function (result) {        // process result        $('#result').html(result.ip);    },    error: function (e) {         // log error in browser        console.log(e.message);    }
});

 

If you don't have to call a service from a different domain, you can remove the jsonpCallback property and change the dataType to json or something else (e.g. XML). You can try out this code snippet right here. Don't forget to read the documentation of jQuery.ajax.

 

Iterate over a JSON structure

 

Sometimes it's very important to handle a complex json response. For example, you want to show all objects of your result in a table or a row repeater. If you can't use the built-in functions of SAPUI5 you can use this:

 

// Object
var person = {    'firstName': 'John',        'lastName': 'Smith',        'age': 25,        'address': {        'streetAddress': '21 2nd Street',            'city': 'New York',            'state': 'NY',            'postalCode': 10021    },        'phoneNumbers': [{        'type': 'home',            'number': '212 555-1234'    }, {        'type': 'fax',            'number': '646 555-4567'    }]
};

// Read single properties
$('#name').html(person.firstName + ' ' +person.lastName);
$('#age').html(person.age);

// Read Array of phone numbers
$.each(person.phoneNumbers, function () {
     // this represents one entry of the array    $('#phoneNumbers').append($('<div class="number"></div>').html(this.type + ' : ' + this.number));
});

 

You can try out this code snippet right here. Don't forget to read the documentation of jQuery.each.

 

Create a new jQuery function

 

If you want to enhance the functionality of jQuery, then check out the extend-function. In this way you can create a new function, which will be available over the jQuery or $ object. (By the way: '$' is just a shortcut of jQuery). This is very useful, if you have to create util or helper functions.

 

// extend jQuery
$.extend($, {  createText: function () {       // create some text in container       $('#container').append('<span>some text</span>');  }
});
// click-handler
$('#create').click(function(){    // call new function    $.createText();
});

 

Test the complete snippet here. Documentation of jQuery.extend.

 

Create a new jQuery instance method

 

When you select a DOM-Element with jQuery, e.g. $('.row'), the framework will return a new jQuery object. You can access over this instance to all kinds of methods. But there is also a way to create new instance methods.

 

// create new instance method
$.fn.extend({    colorize: function () {       this.css('background-color','#f2aa00');    }
});
// click-handler
$('button').click(function(){    // call new instance method    $('.target').colorize();
});

 

A very smart way to implement new stuff! Test the complete snippet here. Documentation of jQuery.fn.extend.

 

Simple data storage with jQuery

 

With HTML5 you can use persistent localStorage or temporarily sessionStorage API to save data in an appropriate scope. But jQuery offers an additional DOM-based method to store temporary arbitrary data.

 

// store data
$("body").data("data_one", 500);
$("body").data("data_two", 52);

$('button').click(function(){

    // read data    var data_one = $("body").data("data_one");    var data_two = $("body").data("data_two");    // create result string    $("div").html('Value: ' + data_one + ' and ' + data_two);
});

 

You can also store e.g. a serialized Javascript Object. But when you left the current site, the DOM-Element will be destroyed and your data will be lost. So it's important to know, that you shouldn't use this API to store session or persistent data. Code snippet is available here. Documentation of jQuery.data.

Simple SAPUI5 Chrome icon for lazy developers like me

$
0
0

I created a Chrome "hosted app" manifest to get a large start page icon with which I could navigate directly to this excellent content resource. Now I can get to my favourite area on SCN in even less time! :-)

 

scn_sapui5_results.png

 

See the project on Github: https://github.com/qmacro/sapui5-chrome-icon

 

Share and enjoy!

Solving "Same Origin Policy" Issue in different ways

$
0
0

Same Origin Policy. Is that really necessary?

 

SOP is an important security concept in browsers. Put simply, SOP allows client-side programming languages, such as JavaScript, only access to resources in the same domain. First picture shows the problem. SOP is very important for internet applications, because you want to prevent, that everybody can access to your services and content. However, this regulation is often unnecessary and obstructive in enterprise environments. Because it's no option to turn down your browser security config, I will show you, how you can solve this problem in different ways.

 

SOP_problem.jpg

 

1. Use JSONP to make cross-domain Ajax requests

 

In my previous post, I explained how you can call a web service from a different domain with jQuery, without getting security issues. This approach is sometimes very useful and easy to implement. But when you can't enhance your services to provide JSONP (or maybe you just refuse to do this), there are some other solutions to handle this problem.

 

2. Establish a Reverse Proxy with Apache HTTP Server

 

2.1 The theory

 

A reverse proxy is a special kind of a web server. This text passage from the official documentation explains very precisely the features:

 

A reverse proxy (or gateway) appears to the client just like an ordinary web server. No special configuration on the client is necessary. The client makes ordinary requests for content in the name-space of the reverse proxy. The reverse proxy then decides where to send those requests, and returns the content as if it was itself the origin.


A typical usage of a reverse proxy is to provide Internet users access to a server that is behind a firewall. Reverse proxies can also be used to balance load among several back-end servers, or to provide caching for a slower back-end server. In addition, reverse proxies can be used simply to bring several servers into the same URL space.

 

The last sentence is very important for us to prevent SOP. The following picture shows the enhanced infrastructure.

SOP_solution.jpg

  1. SAPUI5-Apps will no longer be available under http://myapps.com/, but under http://central.com/apps/.
  2. SAP NetWeaver will no longer be avaiable under http://saphrp.mycompany.com/, but under http://central.com/saphrp/.
  3. IIS will no longer be avaiable under http://otherservices.com/, but under http://central.com/otherservices.

 

All systems are in the same domain, so you can call services without getting security issues.

 

2.2 The practice

 

Now i will show you, how you can test the functionality of a reverse proxy on your local PC. I will use Windows 7 as operating system and the windows version of Apache HTTP Server. Before we start, just a short note: If you are going to work with Apache HTTP Server in your company, i recommend to use UNIX/Linux as OS and not Windows. Besides, you will need a system engineer or a web-admin to create a complete environment with a thorough configuration. Important issues are security, load-balancing and caching.

 

2.2.1 Download Apache HTTP Server

 

As you can see on this site, you can choose different kind of options for deploying Apache httpd on Windows. We will use the server of Apache Lounge. Go to this site an download the latest version Apache win32 binaries (e.g. httpd-2.4.4-win32.zip).

 

apache_download.png

 

2.2.2 The Setup

 

After downloading, unzip the Apache<version> folder to C:\Apache<version> (that is the ServerRoot in the config). When you unzip to an other location, you have to do some changes in the configuration. For testing, it's better to use C:\Apache<version> (in my example: C:\Apache24).

 

2.2.3 Start the Server

After that, open your console and go to C:\Apache24\bin and start the httpd.exe. When everything is fine, you should see a console like this.

apache_start.png

Now the server is running. The message AH00558 is just a warning. To fix this, go to C:\Apache24\conf and open the httpd.conf file (this is the place, where all important configurations are done). Search for 'ServerName' and remove the hash at the start of line (so it's no longer a comment). For our test, you can choose any kind of name, for exaple:

ServerName www.test.com:80

When you now restart the Server (press Ctrl+C in console and start httpd.exe again), the message should be disappeared.

 

apache_start_w_message.png

 

2.2.4 Test

 

Open your browser an call http://localhost. You should see a simple "It works!". When you have problems to start your server, make sure that no other service is running under port 80. Besides, be sure that you have installed the Visual C++ 2010 SP1 Redistributable Package x86. You can download it from here. If you want to check an error.log for more information, go to C:\Apache24\logs and open error.txt.

 

2.2.5 Activating Modules for Reverse Proxy

 

Apache supports a variety of features, many implemented as compiled modules which extend the core functionality. To activate the basic reverse proxy features for HTTP, go to C:\Apache24\conf and open httpd.conf. Remove the hash at LoadModule proxy_module modules/mod_proxy.so and LoadModule proxy_http_module modules/mod_proxy_http.so. Restart your server.

mod.png

2.2.6 Adding a simple Configuration

 

Let's say, we no longer want to call the start page of amazon.com over http://www.amazon.com but over localhost/amazon. Add in your httpd.conf at the end of file this two lines:

 

ProxyPass /amazon http://www.amazon.com/

ProxyPassReverse /amazon http://www.amazon.com/

Restart your server and go to localhost/amazon. You should see the start page of amazon.com! And that's it!

 

2.3 Some more Information

 

This was just a tiny and minimal configuration for reverse proxy functionality. For enterprise environments, you will need a lot of more configuration in order to cover all requirements. Some issues of this solution, which can be solved by adding additional modules and configuration, are listed here:

 

  1. When you click on a link on localhost/amazon, you will get a HTTP 404 Error. You have to ensure, that all resources of a domain are available over your reverse proxy.
  2. For stateful applications (where you have a session context), you have to use further modules, which handle the communication between reverse proxy and server over a specific protocol. For Java-Servers (Tomcat, Jetty etc.) you can use mod_proxy_ajp or mod_jk, which implement the Apache JServ Protocol.
  3. For SAP NetWeaver Gateway or ICF-based services i only know how to implement a stateless communication between SAPUI5-App, ReverseProxy and Application Server. If you need a session-context on your server, i can't say, if Apache HTTP Server is supporting this.
  4. For SSL-support, you need further modules like mod_ssl.
  5. If you want to deliver a query string to an application server(this is normally very important for SAPUI5-Apps), you will need a rewrite engine like mod_rewrite.

 

Beside AJP and HTTP, you can use a reverse proxy for other protocols, too. Currently there are modules for AJP, HTTP, CONNECT(for SSL), FastCGI, ftp and SCGI.

 

3. Cross-origin resource sharing

 

An other approach to solve SOP is Cross-origin resource sharing (CORS). This article of mozilla developer network explained very well the characteristics of CORS. Here a little extract:

 

Cross-site HTTP requests initiated from within scripts have been subject to well-known restrictions, for well-understood security reasons.  For example HTTP Requests made using the XMLHttpRequest object were subject to the same-origin policy.  In particular, this meant that a web application using XMLHttpRequest could only make HTTP requests to the domain it was loaded from, and not to other domains.  Developers expressed the desire to safely evolve capabilities such as XMLHttpRequest to make cross-site requests, for better, safer mash-ups within web applications.

 

The Cross-Origin Resource Sharing standard works by adding new HTTP headers that allow servers to describe the set of origins that are permitted to read that information using a web browser.

 

To test this feature, look at the header-data of this service: http://ip.jsontest.com/.

 

cors.png

When you call this service with jQuery without JSONP, you will still get an answer (you can test this call right here). This is only possible because of the response header "Access-Control-Allow-Origin".

 

This solution means, that you don't have to establish an additional server instance in your infrastructure. Instead, you have to enhance your services with HTTP-Headers. There are some ways, how you can achieve this.

 

3.1 Example for ICF-based Services

 

When you create simple HTTP-Services with ICF, you can add very easily additional header information. Besides, you can implement this feature in an own HTTP-Handler-Class, which will be added to your Handler-List in SICF.

 

SERVER->response->set_header_field(      EXPORTING          name = 'Access-Control-Allow-Origin'          value = '*'
).

 

3.2 Example for a Java-Filter

 

When you can't configure your Java-Server to add new headers, you can write a simple filter for your web-application to add CORS-Headers.

 

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class CORSFilter implements Filter {

          public CORSFilter() {          }          public void init(FilterConfig fConfig) throws ServletException {          }          public void destroy() {          }          public void doFilter(ServletRequest request, ServletResponse response,                              FilterChain chain) throws IOException, ServletException {                    ((HttpServletResponse) response).addHeader(                                        "Access-Control-Allow-Origin", "*");                    chain.doFilter(request, response);          }
}

 

This is the enhancement for your web.xml.

 

<filter><filter-name>CORSFilter</filter-name><filter-class>CORSFilter</filter-class></filter><filter-mapping><filter-name>CORSFilter</filter-name><url-pattern>/service/*</url-pattern></filter-mapping>

 

3.3 Adding Header-Field with Server-Config

 

It depends on your server, if it's possible and how easy it is to add custom header-fields. A short interview with your admins should give you more information.

 

I hope, all this information will help you to get rid of SOP. I wish you success!

Viewing all 789 articles
Browse latest View live




Latest Images