You are on page 1of 73

SAP HANA NATIVE DEVELOPMENT

XS-BASED DEVELOPMENT
DEV160
Exercises / Solutions
Thomas Jung / SAP Labs, LLC.
Yuval Morad / SAP Labs ISR
Diego Rapela / SAP SE

DEV160
Table of Contents
Getting Help .........................................................................................................................3
Source code solutions ..........................................................................................................3
Exercise 1 Setup of a Project ................................................................................................ 4
Exercise 1 Solution................................................................................................................5
Exercise 1.1: Create a connection to the HANA server ....................................................... 5
Exercise 1.2: Create group package and initial project contents ....................................... 10
Exercise 1.3: Create a Repository Workspace ................................................................... 14
Exercise 1.4: Check out the project in HANA Studio .......................................................... 15
Exercise 1.5: Grant the Developer Role ............................................................................. 17
Exercise 1.6: Creating and running a Hello World HTML page from our Project ............... 19
Exercise 2 Creating Database Objects via the Repository .................................................. 23
Exercise 2 Solution..............................................................................................................24
Exercise 2.1: Creating the hdbdd development artifact ...................................................... 24
Exercise 2.2: Defining reusable types and structures ........................................................ 27
Exercise 2.3: Defining database tables and views ............................................................. 28
Exercise 3 Services ..............................................................................................................35
Exercise 3 Solution..............................................................................................................36
Exercise 3.1: Creating a Hello World XSJS Service .......................................................... 36
Exercise 3.2: Creating an XSJS Service with custom output format .................................. 39
Exercise 3.3: Creating a Simple OData Service ................................................................. 43
Exercise 3.4: Creating an OData Service with an Entity Relationship................................ 48
Exercise 3.5: Creating an OData Service with Create Operation and XSJS Exit ............... 51
Exercise 4 User Interface ....................................................................................................55
Exercise 4 Solution..............................................................................................................56
Exercise 4.1: Consume a Basic OData Service within UI5 binding the service to a Table 56
Exercise 4.2: Use oData Metadata to dynamically create the columns.............................. 60
Exercise 4.3: Use oData Metadata with SAP Annotation OData4SAP .............................. 62
Exercise 4.4: Create a Fiori Launchpad Site ...................................................................... 65

DEV160
BEFORE YOU START
System Host: lt5081.wdf.sap.corp
System Instance Number: 10
Desktop User: student
System User ID: DEV160_<group number>. Your group number will
be given to you by the session instructor. For example if the group
number is 001, then your user id would be DEV160_001
System Password: Welcome14

Getting Help

If you need addition help resources beyond this document, we would suggest the following
content:

The Online Help at http://help.sap.com/hana/SAP_HANA_Developer_Guide_en.pdf


The integrated help within SAP HANA Studio (content identical to the above mentioned online
help)
SAPUI5 SDK (installed on your HANA Server)
http://lt5081.wdf.sap.corp:8010/sap/ui5/1/sdk/index.html#content/Overview.html

Source code solutions


All source code solutions and templates for all exercises in this document can be found in the
following webpage.
http://lt5081.wdf.sap.corp:8010/workshop/admin/ui/exerciseMaster/?workshop=dev160
In some cases it might be a little easier to copy and paste the coding instead of typing it all manually.
If copying/pasting, I would suggest that you make sure to understand what is being copied/pasted
before moving on.
Open the browser and enter the following URL to access the solutions web page. You can access the
source code for each exercise by clicking on the appropriate exercise in the navigation bar.
http://lt5081.wdf.sap.corp:8010/workshop/admin/ui/exerciseMaster/?workshop=dev160
Please Note: you will need your username and password to access this site.

DEV160

EXERCISE 1 SETUP OF A PROJECT

Objective
In this exercise, you will learn the basics of creating a workspace and creating an XS project which
you will use for the remainder of this workshop.

Exercise Description
Create a system connection in SAP HANA Studio
Create a workspace which is linked to the HANA Server
Create a project which is linked to the workspace
Create a schema
Create access control files
Create a role
Create a HelloWorld.html file to test your setup

DEV160
EXERCISE 1 SOLUTION
Exercise 1.1: Create a connection to the HANA server

Explanation

Screenshot

1) Launch the HANA Studio


from the Start Menu. It can
be found in SAP -> SAP
HANA. Choose the link for
this particular session
SAP HANA Studio
DEV160.

2) Click Window, then


Preferences.

DEV160

3) Expand General, and


choose Web Browser.
Then click Search.

4) Expand C: and select


Program Files(x86). Click
Ok.

DEV160

5) Select Chrome from the


list, and click Apply, then
Ok.

6) Make sure you are in the


SAP HANA Development
perspective by clicking on
the button.
.
7) Click on the Systems
view. Right click in the
white space below this tab
and choose Add
System.

DEV160

8) Input the server hostname:


lt5081.wdf.sap.corp
Input the instance number:
10
Enter a meaningful
description of your choice.
Press the Next button.

9) Enter the user id and


password which the
instructor has provided to
you. The user id should
be DEV160_<group
number>. Your group
number will be given to you
by the session instructor.
For example if the group
number is 01, then your
user id would be
DEV160_001.
Enter the password:
Welcome14
Click Store user name and
password in secure
storage.
Click Finish.

DEV160

10) You should now have a


new connection with your
specific user id for the
HANA system. Please
make sure to use this
connection for the rest of
the exercise.

DEV160
Exercise 1.2: Create group package and initial project contents

Explanation

Screenshot

1) We also have some


browser based tools and
wizards that can be used
along with the HANA Studio
to speed up development.
We will use the HANA
Application Lifecycle
Management tool to setup
our initial project structure.
Open Google Chrome from
the Desktop
2) Input URL for your HANA
system
http://lt5081.wdf.sap.corp:8
010
Then the path to the HANA
Lifecycle Management tool
(/sap/hana/xs/lm/).
The full URL for this
system is:
http://lt5081.wdf.sap.corp:8
010/sap/hana/xs/lm/
3) Input the same user name
and password you used to
logon to the HANA System
via the Studio

10

DEV160

4) Navigate to the Products


tab and then the Packages
tab

5) Expand dev160 and then


select the exercises folder.
Press the large + Create
button in the upper left
corner to create a new
package.

11

DEV160

6) Check to make sure the full


package path of
dev160.exercises is
correct.
Create a package with
g<three digit group
number>. In our example
we are group number 000.
Therefore our value is
dev160.exercises and
g000.
Press Create.

7) It might take a few


seconds, but you should
receive a message on the
status bar at the bottom of
the browser window that
the package was
successfully created.
8) Expand the exercises
package and you should
see your newly created
group package. Select
your group folder. Then
press Create Application.

12

DEV160

9) Check Require
Authentication.
Check Create Schema and
input a Schema named
HANA_DEV160_<Group
Number>. For this
example this would be
HANA_DEV160_000.
Also Select Create
Developer Role. Name
your Role developer.
Check Create Eclipse
Project and make the
project name
DEV160_<Group
Number>.
Check Create index.html
file.
Press Create.

10) You should receive a


series of messages that
access objects, a schema,
an Eclipse project and a
role have all been created.
PLEASE NOTE: You will
not see these objects
which were just created in
the package hierarchy. The
HALM tool only displays
packages, not their
content. You will see this
content in subsequent
steps.
You now have the start of a
basic project, including a
Schema and the local
developer role with access
to it all.

13

DEV160
Exercise 1.3: Create a Repository Workspace

Explanation

Screenshot

We can now return to the SAP


HANA Studio.

We can now return to the SAP HANA Studio.

1) Switch to the SAP HANA


Repositories view. Click
the icon for Create
Repository Workspace.

2) Select the system entry


you created previously.
Keep all other fields at their
default values and choose
Finish..

3) You should now see the


new workspace in the SAP
HANA Repositories view.
PLEASE NOTE: Your User
ID will be different than
those displayed in
subsequent screen shots.

14

DEV160
Exercise 1.4: Check out the project in HANA Studio

Explanation

Screenshot

1) Expand the Repository


entry you created earlier.
Inside your group package,
you will see all the objects
created by the wizard in
the previous steps. You
can now right mouse click
on your group package and
choose Check Out and
Import Projects

2) Press Next

15

DEV160

3) To complete the import of


the project, choose Finish.

4) Switch to the Project


Explorer View. You
should see that your
project is now available for
development and shared to
the HANA repository.

16

DEV160
Exercise 1.5: Grant the Developer Role

Explanation

Screenshot

1) The application creation


wizard also created a local
developer role which will
give your user access to
create objects in this new
schema. We need only
grant this role to your user.
Open the SQL Console by
right mouse clicking on the
SAP HANA System Library
node in your project and
choosing SQL Console

2) You will need to call a


SQLScript Procedure to
perform the grant. This
procedure will run as
SYS_REPO and therefore
can grant the role to your
user (note: Access to
execute this procedure
should be extremely limited
since it gives anyone who
has it great power). The
Procedure you need to call
is
GRANT_ACTIVATED_ROL
E which has two input
parameters ROLENAME
create in the wizard and
your USERNAME.
Note: if you dont want to
type this code, we
recommend that you cut
and paste it from this web
address
http://lt5081.wdf.sap.corp:8
010/workshop/admin/ui/exer
ciseMaster/?workshop=dev
160&sub=ST_3
Press the green execute
button.

17

DEV160

3) Your user now has the


assigned role

18

DEV160
Exercise 1.6: Creating and running a Hello World HTML page from our Project

Explanation

Screenshot

1) Finally we want to add a


simple hello world html file
to our application in order to
test the security and setup
of our project. We could do
this manually from the
HANA Studio project or use
the index.html created by
the wizard, but this also an
opportunity to try out the
Browser Based IDE the
SAP HANA Web-based
Development Workbench.
2) Input URL for your HANA
system
http://lt5081.wdf.sap.corp:8
010
Then the path to the HANA
Web Workbench
(/sap/hana/xs/ide/editor/).
Complete URL would be:
http://lt5081.wdf.sap.corp:8
010/sap/hana/xs/ide/editor/
3) Input the same user name
and password you used to
logon to the HANA System
via the Studio if prompted
for authentication.
If you had not closed your
web browser from the
previous work, then the
authentication would still
be active in the browser.

19

DEV160

4) The Web Workbench has


the same repository tree as
we have access to in the
HANA Studio. The
difference here is that we
dont check out projects,
but instead directly edit and
save objects. Commit and
Activate are both
performed upon save.

5) The Web Workbench also


has some project wizards.
Right mouse click on your
group folder and choose
Create Application

6) In the Create Application


from Template dialog, input
a new folder named
HelloWorld.
Choose the template
HANA UI5 Hello World.
Then press Create.

20

DEV160

7) Your group folder now


contains a sub-folder
named HelloWorld with a
basic html example.

8) Select the index.html file


and then press the Run
button in order to test it.

9) The index.html file should


open in a new browser
window.
This simple test tells us
that your project, role and
access control files are all
setup properly.

21

DEV160

10) If you return to the HANA


Studio and your Project in
the Project Explorer; you
can right mouse click and
choose Team ->Check Out

11) All the content created in


the Web Workbench is now
copied into our local
project. This allows you to
move between either
development environments
as you work.

12) You have completed the


exercise!

You are now able to:

Create a connection to the HANA server in HANA Studio


Create a workspace which is linked to the HANA Server
Create a project which is linked to the workspace
Create a schema
Create access control files
Create a role
Create a HelloWorld.html file to test your setup

22

DEV160

EXERCISE 2 CREATING DATABASE OBJECTS VIA THE


REPOSITORY
Objective
In the past, database objects could only be created via SQL directly in the database catalog. However
this meant they couldnt be transported via delivery units like all other repository objects. As part of
HANA Native Development, we now have tools to create database objects via a repository
representation which generates the catalog objects upon activation.

Exercise Description
We created a schema to hold all of our database objects in Exercise 1.Next we will use the
development object (new as of SPS6) hdbdd which utilizes the CDS syntax to define reusable
types, structures, tables and views.
For example:
Create a HDBDD object
Use CDS Syntax to define types, structures and tables

23

DEV160
EXERCISE 2 SOLUTION
Exercise 2.1: Creating the hdbdd development artifact

Explanation

Screenshot

1) We will create all of our


database objects within
the data folder of our
project. This simply helps
keep the various parts of
our application separated
for easier use and
maintenance. Create a
new folder called data by
right-clicking on the
project and choosing
New, then Folder.
Name the folder data.
We now want to create
two database tables one
for purchase order
headers and one for
items. Also, we will create
a view based on those
two tables. All of these
objects will be created via
a single development
object called
PurchaseOrder.hdbdd.
Begin this process by
right mouse clicking on
the data folder in your
project and choosing New
-> Other.

24

DEV160

2) In the New wizard,


expand the SAP HANA
folder, expand the
Database Development
folder and choose DDL
Source File. Then press
Next.

3) Verify that the data folder


is selected. Type the
filename PurchaseOrder.
The file extension hdbdd
will be added
automatically for you.
Finally, press Finish.

25

DEV160

4) The hdbdd file is opened


in the editor with the
correct namespace and
context already entered
for you.

5) Next we need to tell the


HDBDD file which
schema all objects should
be created within. Correct
the @Schema line after
the namespace but before
the context and supply the
name of the Schema you
created in the previous
exercise:
HANA_DEV160_<Group
Number>. For this
example this would be
HANA_DEV160_000.

26

DEV160
Exercise 2.2: Defining reusable types and structures

Explanation

Screenshot

type
type
type
type
type
type

1) First we need to define


some reusable elemental
types. These will later be
used to define the data
type of individual columns
in our tables.
Within the PurchaseOrder
context, create element
types for BusinessKey,
SDate, CurrencyT,
AmountT, QuantityT,
UnitT, and StatusT.

BusinessKey : String(10);
SDate : LocalDate;
CurrencyT : String(5);
AmountT : Decimal(15,2);
QuantityT : Decimal(13,3);
UnitT: String(3);

type StatusT: String(1);

Note: if you dont want to


type this code, we
recommend that you cut
and paste it from this web
address
http://lt5081.wdf.sap.corp:8
010/workshop/admin/ui/ex
erciseMaster/?workshop=d
ev160&sub=DB_1

2) We can also create


reusable structures with
multiple fields. This is
useful when the same
sets of fields are repeated
in multiple tables. Create
a reusable structure for
History with
CREATEDBY,
CREATEDAT,
CHANGEDBY, and
CHANGEDAT fields.

Type HistoryT
CREATEDBY
CREATEDAT
CHANGEDBY
CHANGEDAT

};

Note: if you dont want to


type this code, we
recommend that you cut
and paste it from this web
address
http://lt5081.wdf.sap.corp:
8010/workshop/admin/ui/e
xerciseMaster/?workshop
=dev160&sub=DB_2

27

{
:
:
:
:

BusinessKey;
SDate;
BusinessKey;
SDate;

DEV160
Exercise 2.3: Defining database tables and views

Explanation

Screenshot

@Catalog.tableType : #COLUMN
Entity Header {
key PURCHASEORDERID: BusinessKey;
HISTORY: HistoryT;
NOTEID: BusinessKey null;
PARTNER: BusinessKey;
CURRENCY: CurrencyT;
GROSSAMOUNT: AmountT;
Note: if you dont want to
NETAMOUNT: AmountT;
type this code, we
recommend that you cut
TAXAMOUNT: AmountT;
and paste it from this web
LIFECYCLESTATUS: StatusT;
address
APPROVALSTATUS: StatusT;
http://lt5081.wdf.sap.corp:8
CONFIRMSTATUS: StatusT;
010/workshop/admin/ui/ex
erciseMaster/?workshop=d
ORDERINGSTATUS: StatusT;
ev160&sub=DB_3
INVOICINGSTATUS: StatusT;
};

1) The syntax for creating


Entities is similar to types.
Entities will become
database tables when
activating the hdbdd file.
Create a purchase order
entity with these fields and
types:

@Catalog.tableType : #COLUMN
Entity Item {
key HEADER: Association [1] to Header
Note: if you dont want to
{PURCHASEORDERID};
type this code, we
recommend that you cut
key PURCHASEORDERITEM: BusinessKey;
and paste it from this web
PRODUCT: BusinessKey;
address
NOTEID: BusinessKey null;
http://lt5081.wdf.sap.corp:
CURRENCY: CurrencyT;
8010/workshop/admin/ui/e
GROSSAMOUNT: AmountT;
xerciseMaster/?workshop
=dev160&sub=DB_4
NETAMOUNT: AmountT;
TAXAMOUNT: AmountT;
QUANTITY: QuantityT;
QUANTITYUNIT: UnitT;
DELIVERYDATE: SDate;

2) Repeat this process for


the Item Entity.

};

define view ItemView as SELECT from Item {


HEADER.PURCHASEORDERID as
"PurchaseOrderItemId",
Note: if you dont want to
PURCHASEORDERITEM as "ItemPos",
type this code, we
recommend that you cut
PRODUCT as "ProductID",
and paste it from this web
CURRENCY as "CurrencyCode",
address
GROSSAMOUNT
as "Amount",
http://lt5081.wdf.sap.corp:8
NETAMOUNT as "NetAmount",
010/workshop/admin/ui/ex
TAXAMOUNT as "TaxAmount",
erciseMaster/?workshop=d
ev160&sub=DB_5
QUANTITY as "Quantity",
QUANTITYUNIT as "QuantityUnit",

3) Next, add a view for the


Item table.

28

DEV160

};
4) Here is the complete
source code for your
hdbdd file.

DELIVERYDATE as "DeliveryDate1"

namespace dev160.exercises.g<group_number>.data;
@Schema: 'HANA_DEV160_<Group_number>'
context PurchaseOrder {
type
type
type
type
type
type
type

BusinessKey : String(10);
SDate : LocalDate;
CurrencyT : String(5);
AmountT : Decimal(15,2);
QuantityT : Decimal(13,3);
UnitT: String(3);
StatusT: String(1);

Type HistoryT {
CREATEDBY : BusinessKey;
CREATEDAT : SDate;
CHANGEDBY : BusinessKey;
CHANGEDAT : SDate;
};
@Catalog.tableType : #COLUMN
Entity Header {
key PURCHASEORDERID: BusinessKey;
HISTORY: HistoryT;
NOTEID: BusinessKey null;
PARTNER: BusinessKey;
CURRENCY: CurrencyT;
GROSSAMOUNT: AmountT;
NETAMOUNT: AmountT;
TAXAMOUNT: AmountT;
LIFECYCLESTATUS: StatusT;
APPROVALSTATUS: StatusT;
CONFIRMSTATUS: StatusT;
ORDERINGSTATUS: StatusT;
INVOICINGSTATUS: StatusT;
};
@Catalog.tableType : #COLUMN
Entity Item {
key HEADER: Association [1] to Header
{PURCHASEORDERID};
key PURCHASEORDERITEM: BusinessKey;
PRODUCT: BusinessKey;
NOTEID: BusinessKey null;
CURRENCY: CurrencyT;
GROSSAMOUNT: AmountT;

29

DEV160

};

NETAMOUNT: AmountT;
TAXAMOUNT: AmountT;
QUANTITY: QuantityT;
QUANTITYUNIT: UnitT;
DELIVERYDATE: SDate;

define view ItemView as SELECT from Item {


HEADER.PURCHASEORDERID as
"PurchaseOrderItemId",
PURCHASEORDERITEM as "ItemPos",
PRODUCT as "ProductID",
CURRENCY as "CurrencyCode",
GROSSAMOUNT as "Amount",
NETAMOUNT as "NetAmount",
TAXAMOUNT as "TaxAmount",
QUANTITY as "Quantity",
QUANTITYUNIT as "QuantityUnit",
DELIVERYDATE as "DeliveryDate1"
};
};
5) Save and activate your
hdbdd file.

30

DEV160

6) Open the SAP HANA


System Library in your
project and expand the
node for your Schema.
Within Procedures->Table
Types you should find the
structure for your HistoryT
type.
Within Tables you should
see both your
PurchaseOrder.Header
and PurchaseOrder.Item
tables.
Within the Views folder,
you should also see the
view.

7) You can double click on


any of these objects to
open their definition.

31

DEV160

8) For this workshop, we


have created an
application which will verify
the tables in your schema
and input some random
test data for you.
Run this application from
http://lt5081.wdf.sap.corp:8
010/dev160/solutions/ui/cd
sTest.html

9) Input your Schema name


and press Create Data.
HANA_DEV160_<Group
Number>. For this
example this would be
HANA_DEV160_000.

32

DEV160

10) The tables in this page will


then display the newly
inserted data in your
header and item tables.

11) You can return to the


HANA Studio and browse
the data from there as well
by choosing Open Data
Preview

12) The same data from the


web application is now
displayed in the data
preview tool of HANA
Studio.

33

DEV160

34

DEV160

EXERCISE 3 SERVICES
Objective
XSJS or Server Side JavaScript is used to create custom services and is the main imperative and
control flow logic layer in HANA Native Applications. In this exercise we will create simple XSJS
Services, access the database and format data with XSJS services.
The XSEngine contains a special tool for the creation of OData Services without needing to perform
server side coding. To create an OData service from an existing HANA table or view, you need only
define an XSODATA service definition file.

Exercise Description

Create a Hello World XSJS Service


Create an XSJS Service with database access and custom output format
Create a Basic OData Service
Create an OData Service with relationships
Create an OData Service with Create/Update/Delete operations and XSJS exits

35

DEV160
EXERCISE 3 SOLUTION
Exercise 3.1: Creating a Hello World XSJS Service

Explanation

Screenshot

1) We will create all of our


services objects within the
services folder of our
project. This simply helps
keep the various parts of
our application separated
for easier use and
maintenance. First create a
folder called services
using New->Folder.

2) To create the XSJS service


we must create an XS
JavaScript File. A
corresponding New Wizard
can be found under New>Other.

36

DEV160

3) From the New Wizard,


choose XS JavaScript File
from the SAP HANA ->
Application Development
folder

4) Select the services folder.


Name your new source file:
HelloWorld.xsjs.

37

DEV160

5) We want to create a service


which uses the Database
APIs to call a select from
the dummy table and
outputs the results along
with a Hello World text
string.
Note: if you dont want to
type this code, we
recommend that you cut
and paste it from this web
address
http://lt5081.wdf.sap.corp:8
010/workshop/admin/ui/exer
ciseMaster/?workshop=dev
160&sub=XSJS_1
Save and Activate your new
service.

6) Test the service in your


browser by right mouse
clicking on the service file in
the Project Explorer and
choosing Run As->XS
Service.
For example if your group
number was 00 then the
URL would be:
http://lt5081.wdf.sap.corp:8
010/dev160/exercises/g000/
services/HelloWorld.xsjs

38

DEV160
Exercise 3.2: Creating an XSJS Service with custom output format

Explanation

Screenshot

1) Now we want to extend the


concepts of the XSJS
service from the first half of
this exercise. Weve already
seen how we can use our
own custom logic in an
XSJS service. Next we
want to see how we can
use a custom output format.
We will also see how we
can perform SQL to use
data from the database, but
manipulate or format that
returned data. The final
result will be a service
which reads the Business
Partner data but returns it in
a tab delimited format ready
to open in Microsoft Excel.
Using the same steps as
before use the file wizard to
create another xsjs service
named exercise.xsjs.
Note: if you dont want to
type this code, we
recommend that you cut
and paste it from this web
address
http://lt5081.wdf.sap.corp:8
010/workshop/admin/ui/exer
ciseMaster/?workshop=dev
160&sub=XSJS_2
We will explain it block by
block in a moment.

2) First weve added an


import to a reusable library.
We can create such
libraries and share them
between projects and
services. This particular
library helps lookup
reusable language
independent texts from the
database. We will use it to
fill in the column headers of
our Excel export

$.import("sap.hana.democontent.epmNext.services",
"messages");

3) We add a new function to


handle the data retrieval
from the Business Partner
Table and formatting into

function downloadExcel() {
var body = '';

var MESSAGES =
$.sap.hana.democontent.epmNext.services.messages;

39

DEV160

Text Tab Delimited. The


XSJS server side logic
contains various built-in
APIs (referenced via the $
object). Here you see the
usage of the trace object
and the db (database)
objects. We build the SQL
Query and pass it to the
database using syntax very
similar to JDBC or ODBC.
In reality, the XS engine
communicates directly with
the HANA Index server to
retrieve this data
Next you see that we can
build a custom formatted
string in order to get the
text, tab-delimited output
we want. Finally we can
also set any response
headers, which is
necessary to control the
Content-Disposition so the
output acts like a file
download from the
browser.

try {

var query = 'SELECT TOP 25000


"PurchaseOrderId", "PartnerId", "CompanyName",
"CreatedByLoginName", "CreatedAt", "GrossAmount" '
+ 'FROM
"sap.hana.democontent.epmNext.data::EPM.Purchase.Head
erView" order by "PurchaseOrderId"';
$.trace.debug(query);
var conn = $.db.getConnection();
var pstmt = conn.prepareStatement(query);
var rs = pstmt.executeQuery();
body = MESSAGES.getMessage('SEPM_POWRK',
'002') + "\t" + // Purchase
// Order

ID

MESSAGES.getMessage('SEPM_POWRK', '003') +
"\t" + // Partner ID
MESSAGES.getMessage('SEPM_POWRK', '001') +
"\t" + // Company Name
MESSAGES.getMessage('SEPM_POWRK', '004') +
"\t" + // Employee
// Responsible
MESSAGES.getMessage('SEPM_POWRK', '005') +
"\t" + // Created At
MESSAGES.getMessage('SEPM_POWRK', '006') +
"\n"; // Gross Amount
while (rs.next()) {
body += rs.getNString(1) + "\t" +
rs.getNString(2) + "\t"
+ rs.getNString(3) + "\t"
+ rs.getNString(4) + "\t"
+ rs.getDate(5) + "\t" +
rs.getDecimal(6) + "\n";
}
} catch (e) {
$.response.status =
$.net.http.INTERNAL_SERVER_ERROR;
$.response.setBody(e.message);
return;
}
$.response.setBody(body);
$.response.contentType = 'application/vnd.msexcel; charset=utf-16le';
$.response.headers.set('Content-Disposition',

40

DEV160
'attachment; filename=Excel.xls');
$.response.status = $.net.http.OK;
}
4) This block is actually the
entry point to the service
handler but must appear
after all referenced
functions. Here we can
query the request URL and
determine which action to
take. This way a single
XSJS file might have
multiple services or query
parameters. We will look
for the URL parameter
called cmd to decide which
path to take. These are
just examples, as you have
complete control over the
definition of all URL
parameters and how they
are handled by the service

var aCmd = $.request.parameters.get('cmd');


switch (aCmd) {
case "Excel":
downloadExcel();
break;
default:
$.response.status =
$.net.http.INTERNAL_SERVER_ERROR;
$.response.setBody(MESSAGES.getMessage('SEPM_AD
MIN', '002', aCmd));
}

5) Save and Activate your


service.

6) Test the application in your


browser using the Run As
option as previously.
When the application first
launches you will receive an
error because you didnt
give it the cmd parameter.
Add ?cmd=Excel to the end
of the URL.
For example if your group
number was 000 then the
URL would be:

41

DEV160

http://lt5081.wdf.sap.corp:8
010/dev160/exercises/g000/
services/exercise.xsjs?cmd
=Excel

7) If you choose to open the


file attachment, your data
should then show up in
Excel

42

DEV160
Exercise 3.3: Creating a Simple OData Service

Explanation

Screenshot

1) Right mouse click on the


services folder and choose
New->Other.

2) In the New wizard, expand


the SAP HANA and then
Application Development
folders. Choose XS OData
File and then press Next.

43

DEV160

3) Create a new file called


businessPartners.xsodat
a in the services package
of your project.

4) We want to define an
OData service to expose
the business partner table.
The syntax of the
XSODATA service is
relative easy for this use
case. We need only define
a namespace (your
package path), the name
of the HANA Table we will
base the service from (
sap.hana.democontent.e
pmNext.data::EPM.Maste
rData.BusinessPartner)
and the name of the OData
entity (BusinessPartners).
Therefore the content of
the XSODATA file would
be.
Note: if you dont want to
type this code, we
recommend that you cut
and paste it from this web
address
http://lt5081.wdf.sap.corp:8
010/workshop/admin/ui/exe
rciseMaster/?workshop=de
v160&sub=OD_1

44

DEV160

5) Save and activate the file.

6) Now run the service from


Chrome.
In the Studio, select the file
and choose Run As ->XS
Service.
The service will open in
your default browser (if not
Chrome, you can cut and
paste the URL and then
reload in Chrome).
Use your database user
and password to
authenticate for the service.

7) The resulting document


describes the service
entities. We only had the
one entity named
BusinessPartners.

45

DEV160

8) You can now adjust the


URL slightly and add the
/$metadata parameter to
the end of it.
For Example:
http://lt5081.wdf.sap.corp:8
010
/dev160/exercises/g000/ser
vices/businessPartners.xso
data/$metadata

You can see the field


descriptions for all the
attributes of the OData
service.

9) In order to view the data of


the entity, you would
append BusinessPartners
to the end of the URL:
For Example:
http://lt5081.wdf.sap.corp:8
010/dev160/exercises/g000/
services/businessPartners.x
sodata/BusinessPartners
You are now able to see the
data from the
businessPartner table.
10) You can also experiment
with standard OData URL
parameters like $top, $skip,
or $filter. These options are
interpreted and handled by
the OData service of the
XSEngine for you. You get
complex service handling
without any coding. For
example the following URL
would return only three
business partner records
and would skip the first five
records. Such parameters
are helpful when
implementing server side
scrolling, filtering, or sorting
in table UI elements.
For Example:
http://lt5081.wdf.sap.corp:8
010/dev160/exercises/g000/
46

DEV160

services/businessPartners.x
sodata/BusinessPartners?$t
op=3&$skip=5

11) The direct test of the OData


service within a browser is
fine for development
testing; but this is hardly
how end users will interact
with the service. The OData
service is normally called
from within a web page. We
have a test web page which
can dynamically call your
service. It can be accessed
at the URL:
http://lt5081.wdf.sap.corp:8
010/dev160/solutions/ui/oda
taTest.html
The first tab lets you test
this simple service. The
other tabs will be used to
test later parts of this
exercise. Fill your Service
Path and Entity name and
press Execute Service to
test your service.

47

DEV160
Exercise 3.4: Creating an OData Service with an Entity Relationship

Explanation

Screenshot

1) The first example of this


exercise was very
simplistic because it
only exposed one
database table as a
single entity. Often you
need to also represent
relationships between
multiple entities. For
example we might want
to build an OData
service which has both
the Purchase Order
Header and Items. For
this we would build a
1:many relationship
between the two
entities.

2) Returning to HANA
Studio, you should now
create a new OData
service named
purchaseOrders.xsodat
a and extend it to
include the
sap.hana.democontent.
epmNext.data::EPM.Pu
rchase.Header and
sap.hana.democontent.
epmNext.data::EPM.Pu
rchase.Item tables.
Next create a
navigation 1:many
association.
The new content of the
definition file should
look like this:
Note: if you dont want
to type this code, we
recommend that you cut
and paste it from this
web address
http://lt5081.wdf.sap.cor
p:8010/workshop/admin
/ui/exerciseMaster/?wor
kshop=dev160&sub=O
D_2
Save and Activate the
service.

48

DEV160

3) Test using the same


steps as in the previous
section of this exercise.
For example if your
group number was 000
then the URL would be:
http://lt5081.wdf.sap.cor
p:8010/dev160/exercise
s/g000/services/purcha
seOrders.xsodata
Notice that the base
service definition now
has two entities
4) The Header data now
has a hyperlink
relationship to the item
entity

5) Once again you can


return to the test web
page which can
dynamically call your
service. It can be
accessed at the URL:
http://lt5081.wdf.sap.cor
p:8010/dev160/solution
s/ui/odataTest.html
The second tab (MultiEntity Read) lets you
test this multi-entity
service. Fill your
Service Path and Entity
name and press
Execute Service to test
your service. Select a
PO Header Record to
load the correct items
for the header.

49

DEV160

6) Associations can be an
excellent way to load
child elements on
demand; however there
is also an option to
expand the children
details in place so that
all levels can be
retrieved with one
request.
Test the service again
using the same steps
as in the previous
section of this exercise.
This time add
$expand=POItem to the
end of the URL.
You will then see that
all the items are
embedded within each
header record.
Full URL:
http://lt5081.wdf.sap.cor
p:8010/dev160/exercise
s/g000/services/purcha
seOrders.xsodata/POH
eader/?$format=json&$
expand=POItem

50

DEV160
Exercise 3.5: Creating an OData Service with Create Operation and XSJS Exit

Explanation

Screenshot

1) Create another OData


service named
user.xsodata for table
sap.hana.democontent.
epmNext.data::EPM.Us
er.Details. This time,
also link the create
operation to the Server
Side JavaScript Library
(XSJSLIB)
sap.hana.democontent.
epmNext.services::user
sCreateMethod.xsjslib
and the function
usersCreate. This will
be the exit code that
performs validation
before the insert of the
new record.
Note: if you dont want
to type this code, we
recommend that you cut
and paste it from this
web address
http://lt5081.wdf.sap.cor
p:8010/workshop/admin
/ui/exerciseMaster/?wor
kshop=dev160&sub=O
D_4

2) We are sharing the


same Server Side
JavaScript Function for
creation, but here is the
code of this Function for
you to study.

$.import("sap.hana.democontent.epmNext.services",
"session");
var SESSIONINFO =
$.sap.hana.democontent.epmNext.services.session;
51

DEV160

/**
@param {connection} Connection - The SQL connection
used in the OData request
@param {beforeTableName} String - The name of a
temporary table with the single entry before the
operation (UPDATE and DELETE events only)
@param {afterTableName} String -The name of a
temporary table with the single entry after the
operation (CREATE and UPDATE events only)
*/
function usersCreate(param){
let after = param.afterTableName;
//Get Input New Record Values
var pStmt =
param.connection.prepareStatement('select * from "' +
after + '"');
var User =
SESSIONINFO.recordSetToJSON(pStmt.executeQuery(),
'Details');
pStmt.close();
//Validate Email
if(!validateEmail(User.Details[0].E_MAIL)){
throw 'Invalid email for ' +
User.Details[0].FIRSTNAME +
' No Way! E-Mail must be valid and ' +
User.Details[0].E_MAIL + ' has problems';
}
//Get Next Personnel Number
pStmt =
param.connection.prepareStatement('select
"sap.hana.democontent.epmNext.data::purchaseOrderId".
NEXTVAL from dummy');
var rs = pStmt.executeQuery();
var PersNo = '';
while (rs.next()) {
PersNo = rs.getString(1);
}
pStmt.close();
Table

//Insert Record into DB Table and Temp Output


for( var i = 0; i<2; i++){
var pStmt;
if(i<1){

52

DEV160
pStmt =
param.connection.prepareStatement('insert into
SAP_HANA_EPM_NEXT."sap.hana.democontent.epmNext.data:
:EPM.User.Details" values(?,?,?,?)' );
}else{
pStmt =
param.connection.prepareStatement('TRUNCATE TABLE "'
+ after + '" ' );
pStmt.executeUpdate();
pStmt.close();
pStmt =
param.connection.prepareStatement('insert into "' +
after + '" values(?,?,?,?)' );
}
pStmt.setString(1, PersNo);
pStmt.setString(2,
User.Details[0].FIRSTNAME);
pStmt.setString(3, User.Details[0].LASTNAME);
pStmt.setString(4,
User.Details[0].E_MAIL);
pStmt.executeUpdate();
pStmt.close();
}
}
function validateEmail(email) {
var re =
/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*
)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[09]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zAZ]{2,}))$/;
return re.test(email);
}

53

DEV160

3) Once again you can


return to the test web
page which can
dynamically call your
service. It can be
accessed at the URL:
http://lt5081.wdf.sap.cor
p:8010/dev160/solution
s/ui/odataTest.html
4) From the third tab
(Creation) you can call
your service and create
a record with the entries
you supply. Create a
record with all fields
filled in. Then try
creating a record
without an email
address and verify that
you receive the custom
error message from the
XSJS Function.

54

DEV160

EXERCISE 4 USER INTERFACE


Objective

In this exercise the services have already been created for you. You will focus on how to consume and
interact with these services from the SAPUI5 user interface technology. We will also see how to create
a Fiori Launchpad page using the UI Integration Services framework in HANA.

Exercise Description

Consume a Basic OData Service within UI5 binding the service to a Table
Use the OData Meta Data to dynamically create the UI5 Table Columns
Uses OData Meta Data with OData4SAP annotation to create table columns with descriptions from
the backend views
Create a Fiori Launchpad Site

55

DEV160

EXERCISE 4 SOLUTION
Exercise 4.1: Consume a Basic OData Service within UI5 binding the service to a Table

Explanation

Screenshot

1) Create a new folder in your


project called ui. Then
create a folder within ui
called odataBasic.

2) Within your odataBasic


folder create a new file
named index.html. Then
create a sub-folder called
odatabasic. Within this
folder we will create our
view and controller named
odataBasic.view.js and
odataBasic.controller.js.

3) To avoid having to do too


much typing, we have
prepared some template
code for you which already
has the index.html
bootstrap code in it.
Note: if you dont want to
type this code, we
recommend that you cut
and paste it from this web
address
http://lt5081.wdf.sap.corp:8
010/workshop/admin/ui/exer
ciseMaster/?workshop=dev
160&sub=OUI_1A

56

DEV160

4) To avoid having to do too


much typing, we have
prepared the
odataBasic.controller.js
template code. In this
example we wont have any
custom event handlers;
therefore the controller is
just the empty controller
structure..
Note: if you dont want to
type this code, we
recommend that you cut
and paste it from this web
address
http://lt5081.wdf.sap.corp:8
010/workshop/admin/ui/exer
ciseMaster/?workshop=dev
160&sub=OUI_1B

5) To avoid having to do too


much typing, we have
prepared some template
code for you which already
has the definition of the
table UI element and the
table columns, but none of
the logic to consume the
OData service. You can cut
and paste this template
code from this address into
the createContent function
of your odataBasic.view.js
file:
Note: if you dont want to
type this code, we
recommend that you cut
and paste it from this web
address
http://lt5081.wdf.sap.corp:8
010/workshop/admin/ui/exer
ciseMaster/?workshop=dev
160&sub=OUI_1
You should notice that
there are two
commented To-Do
sections in this code
which you just copied
into the file. These are

57

DEV160

the most important


parts and will be
completed in the next
few steps.

6) In the first To-Do location


you should add the code to
create a model object
named oModel of type
sap.ui.model.odata.ODataM
odel. Use the provided
service
/sap/hana/democontent/ep
mNext/services/businessPa
rtners.xsodata/. If you need
help writing this code
please refer to the solution
at:

___________________________

http://lt5081.wdf.sap.corp:8
010/workshop/admin/ui/exer
ciseMaster/?workshop=dev
160&sub=OUI_2

7) In the second To-Do


location you should set the
model named oModel to the
table control named oTable.
Create a sorter (type
sap.ui.model.Sorter) which
uses the column PartnerId.
Bind the table to the entity
BusinessPartners and add
the sorter object to the
binding. If you need help
writing this code please
refer to the solution at:

___________________________

http://lt5081.wdf.sap.corp:8
010/workshop/admin/ui/exer
ciseMaster/?workshop=dev
160&sub=OUI_3

58

DEV160

8) Thats all that is necessary


to connect the Table UI
element to the OData
service. We get built in
table sorting and filtering, as
well as server side scrolling
via the various built-in
parameters of the OData
service framework.
Save and Activate your
project.

9) Test your application in a


web browser using the Run
As -> HTML option.
The URL would be
http://<hostname>:<port>/d
ev160/exercises/g<group>/
ui/odataBasic/. For example
if you were in group number
000 your URL would be:
http://lt5081.wdf.sap.corp:8
010/dev160/exercises/g000/
ui/odataBasic/
Try the sort or filter ability
on one of the columns to
test out the built-in features
of the OData Service.
The sample solution is also
available at
http://lt5081.wdf.sap.corp:8
010/sap/hana/democontent/
epmNext/ui/odataBasic/

59

DEV160
Exercise 4.2: Use oData Metadata to dynamically create the columns.

Explanation

Screenshot

1) In the previous part of this


exercise we hard coded all
the table column definitions
in the template. However,
oData services expose all
their meta data and we can
use this feature to build the
columns dynamically.
Return to your view file.
Delete the complete block
of lines after the Table
Column Definitions
comment and before the
oTable.setModel line.

2) You can create a


connection to the metadata
object via the function
getServiceMetadata of your
model object. Inside this
meta data you will find the
columns of the service at
dataServices.schema[0].ent
ityType[0].property. Loop
over this collection and
create a column for each
property.name in the
service dynamically.
If you need help writing this
code please refer to the
solution at:
http://lt5081.wdf.sap.corp:8
010/workshop/admin/ui/exer
ciseMaster/?workshop=dev
160&sub=OUI_4
Save and Activate your
project.

60

DEV160

3) Test your application in a


web browser using the Run
As -> HTML option.
The URL would be
http://<hostname>:<port>/d
ev160/exercises/g<group>/
ui/odataBasic/. For example
if you were in group number
000 your URL would be:
http://lt5081.wdf.sap.corp:8
010/dev160/exercises/g000/
ui/odataBasic/
Notice that you now have all
the columns of the service;
not just the few you had
before.
The sample solution is also
available at
http://lt5081.wdf.sap.corp:8
010/sap/hana/democontent/
epmNext/ui/odataMeta/

61

DEV160
Exercise 4.3: Use oData Metadata with SAP Annotation OData4SAP

Explanation

Screenshot

1) In the previous part of this


exercise we loaded the
column names dynamically.
This was nice but could
have been better if we could
have used column
descriptions. We can do this
using the Annotation
OData4SAP and if our
source is a modeled view
and not a table.
Return to your Exercises
project. Create a new
XSODATA service in the
services folder named
businessPartnersExt.xso
data. Use
sap.hana.democontent.ep
mNext.models::AT_BUYE
R as the source of the
service and add the
annotation.
If you need help writing this
code please refer to the
solution at:
http://lt5081.wdf.sap.corp:8
010/workshop/admin/ui/exer
ciseMaster/?workshop=dev
160&sub=OUI_A
Save and Activate your
service.

2) Return to your view file in


your odataBasic project.
Change the model definition
to point to your new service.

62

DEV160

3) Remove the block of code


from the last section oft he
exercise which dynamically
creates the columns.

4) In the code block we


inserted in the previous
exercise to create the
columns dynamically from
the metadata, change label
text logic to load from the
extensions object. Check
the name of the extension
looking for label and then
pull the value for that
extension.
If you need help writing this
code please refer to the
solution at:
http://lt5081.wdf.sap.corp:8
010/workshop/admin/ui/exer
ciseMaster/?workshop=dev
160&sub=OUI_B

5) Change the sorting column


to PartnerId
Save and Activate your
project.

63

DEV160

6) Test your application in a


web browser using the Run
As -> HTML option.
The URL would be
http://<hostname>:<port>/d
ev160/exercises/g<group>/
ui/odataBasic/. For example
if you were in group number
000 your URL would be:
http://lt5081.wdf.sap.corp:8
010/dev160/exercises/g000/
ui/odataBasic/
Notice that you now have all
the columns of the service;
not just the few you had
before.
The sample solution is also
available at
http://lt5081.wdf.sap.corp:8
010/sap/hana/democontent/
epmNext/ui/odataMetaExt/

64

DEV160
Exercise 4.4: Create a Fiori Launchpad Site

Explanation

Screenshot

1) Since SPS08, the UIS


technology can also be
used to create Fiori
Launchpads with dynamic
tiles.
Create a folder in your
project named uis.
Begin by creating a new
UIS Catalog named
FioriCatalog.xswidget with
the catalog name Fiori
G<your group number>
Catalog.
After the creation wizard is
complete, double click the
new file in the uis folder to
open the Catalog editor.

2) Add a tile to the Catalog


and choose Dynamic App
Launcher as the tile type.

65

DEV160

3) Selected the newly inserted


tile in order to configure it

4) Supply the following basic


information in the General
area

5) In the Dynamic Data area,


provided the following
service URL:
/sap/hana/democontent/ep
mNext/services/poWorklist.x
sodata/PO_WORKLIST/$co
unt?$filter=((LifecycleDesc
%20eq%20%27New%27))
This is the URL to an
XSODATA service for the
Purchase Order worklist. It
will retrieve the number of
New Purchase Orders.

66

DEV160

Also set the refresh interval


to 5 seconds. This way the
tile will live update every 5
seconds.
6) For navigation, uncheck the
Use semantic object
navigation option. Instead
provide the relative URL to
the sample implementation
of the Purchase Order
Worklist:
/sap/hana/democontent/ep
mNext/ui/poworklist/poWork
list.html
This will allow users to click
on this tile in the Launchpad
and open the complete UI
for the Purchase Order
Worklist.
7) Save the Tile Configuration
and return to the Catalog
overview.

67

DEV160

8) Save and activate the


Catalog.

9) Now create a new UIS


application site in the uis
project folder. Name this
Application Site
FioriLaunchPad.xsappsite.
Be sure to select Fiori
Launchpad as the Site
Type.

68

DEV160

10) Add a group named Default

11) Add a tile to this group.

12) Use the value help to


choose a catalog for your
tile.

69

DEV160

13) Type in your group number


in the catalog search dialog
and you should narrow the
list to just your catalog you
created in the previous
steps.

14) Click on the plus icon to add


the Purchase Order Worklist
tile from your catalog to
your new LaunchPad
apposite.

70

DEV160

15) Navigate back to the app


site configuration.

16) Save and activate the


FioriLaunchPad.xsappsite.

17) If you click the gear in the


upper right corner of the
xsappsite editor and choose
Runtime Version; a browser
window will open with the
Launchpad in it.

71

DEV160

18) You should see a


luanchpad with your tile and
the actual number of new
purchase orders. Click on
the tile and the PO Worklist
app will open.

19) In the PO Worklist, select


one of the Purchase Orders
with the Lifecycle Status of
New and delete it.

20) Within 5 seconds the live


tile should now reflect the
newly reduced number of
Purchase Order items with
the status New.

72

DEV160

2015 SAP SE or an SAP affiliate company. All rights reserved.


No part of this publication may be reproduced or transmitted in any form or for any purpose without the express permission of SAP SE or an SAP
affiliate company. SAP and other SAP products and services mentioned herein as well as their respective logos are trademarks or registered
trademarks of SAP SE (or an SAP affiliate company) in Germany and other countries.
Please see http://www.sap.com/corporate-en/legal/copyright/index.epx#trademark for additional trademark information and notices.

73