You are on page 1of 282

SAP HANA EXTENDED APPLICATION

SERVICES, ADVANCED MODEL DEVELOPMENT
SPS 12 Patch 1
Exercises / Solutions
Rich Heilman / SAP Labs, LLC.
Thomas Jung / SAP Labs, LLC.
November 2016

SAP HANA Extended Application Services, Advanced model Development

BEFORE YOU START ................................................................................................................. 4
Getting Help ..................................................................................................................................... 4
Source code solutions ...................................................................................................................... 4

Exercise 1 – Hello World .......................................................................................................... 5
Exercise 1 – Solution ................................................................................................................ 6
Exercise 1.1: HTML5 Module - Hello World ....................................................................................... 6
Exercise 1.2: Clone a Repository from Git ....................................................................................... 14
Exercise 1.3: Alternative: Import Project from File System ............................................................. 18

Exercise 2 –Database Artifact Development .......................................................................... 20
Exercise 2 – Solution .............................................................................................................. 21
Exercise 2.1: Database Content ...................................................................................................... 21
Exercise 2.2: Create Tables & Views via Core Data Services ............................................................ 28
Exercise 2.3: Create Sequences and Table Data Configuration ........................................................ 35
Exercise 2.4: Create Synonym, Structured Privilege & Role ............................................................. 40
Exercise 2.5: Non-Container Schemas, User Provided Services & Synonyms ................................... 43
Exercise 2.6: Cross Container Services & Synonyms ........................................................................ 53
Exercise 2.7 Creating a Graphical Calculation View with a Dimension data type ............................. 61
Exercise 2.8: Creating a Calculation View with a Cube data type and Star Join ................................ 78
Exercise 2.9: Creating the Replacement for the Scripted Calculation View ...................................... 86
Exercise 2.5: Leveraging SQLScript in Stored Procedures & User Defined Functions ........................ 91
Exercise 2.5.1: Creating Stored Procedures ........................................................................................ 91
Exercise 2.5.2: Parallel Processing and Parameters ............................................................................ 95
Exercise 2.5.3: Intermediate Table Variables...................................................................................... 98
Exercise 2.5.4: Creating & Consume a Scalar Function ..................................................................... 101
Exercise 2.5.5: Creating & Consume a Table Functions .................................................................... 105
Exercise 2.5.6: Debugging Stored Procedures .................................................................................. 110
Exercise 2.5.7: Anonymous Blocks .................................................................................................... 116
Exercise 2.5.8: Emptiness Checks...................................................................................................... 119
Exercise 2.5.9: Using Dynamic SQL, SQL Injection prevention Functions, and APPLY_FILTER ......... 123
Exercise 2.5.9.1: Using EXEC Statement ........................................................................................... 123
Exercise 2.5.9.2: Using EXECUTE IMMEDIATE Statement ................................................................. 127
Exercise 2.5.9.3: Using SQL Injection Prevention Functions ............................................................. 129
Exercise 2.5.9.4: Using APPLY FILTER Statement .............................................................................. 134
Exercise 2.5.10: Index Based Cell Access .......................................................................................... 141
Exercise 2.5.11: Exception Handling, COMMIT & Autonomous Transactions .................................. 147
Exercise 2.5.11.1: Using Exception Handling .................................................................................... 147
Exercise 2.5.11.2: Using COMMIT Statement ................................................................................... 153
Exercise 2.5.11.3: Using Autonomous Transactions ......................................................................... 156

2

SAP HANA Extended Application Services, Advanced model Development

Exercise 3 –XSJS and XSODATA services............................................................................... 159
Exercise 3 – Solution ............................................................................................................ 160
Exercise 3.1: XSJS and XSODATA ................................................................................................... 160
Exercise 3.2: Debugging XSJS or Node.js ....................................................................................... 170
Exercise 3.3: Exploring JavaScript Language Features ................................................................... 173
Exericse 3.4: Creating an XSJS Service with outbound HTTP Connectivity...................................... 178
Exericse 3.5: User Provided Service as SQLCC ............................................................................... 181
Exercise 3.6: Creating a Simple OData Service .............................................................................. 184
Exercise 3.7: Creating an OData Service with an Entity Relationship ............................................. 187
Exercise 3.8: Creating an OData Service with Create Operation and XSJS Exit ............................... 190

Exercise 4 – SAPUI5 User Interface ...................................................................................... 194
Exercise 4 – Solution ............................................................................................................ 196
Exercise 4.1: SAPUI5 as an XSA Micro-Service ............................................................................... 196
Exercise 4.2: Creating a Text Bundle ............................................................................................. 199
Exercise 4.3: SAPUI5 User Interface .............................................................................................. 202
Exercise 4.4: Consume XSJS Services via JQuery AJAX calls ........................................................... 213
Exercise 4.5: Consume a Basic OData Service within UI5 binding the service to a Table ................ 218
Exercise 4.6: Use oData Metadata to dynamically create the columns. ......................................... 224
Exercise 4.7: Consume an OData Service with Create Option ........................................................ 226
Exercise 4.8: OData Batch Operation ............................................................................................ 233
Exercise 4.9: OData Deep Insert (Content-ID and Links) ................................................................ 238

Exercise 5 – Node.JS ............................................................................................................ 246
Exercise 5 – Solution ............................................................................................................ 247
Exercise 5.1: Modules and Express ............................................................................................... 247
Exercise 5.2: HANA Database Access from Node.js ....................................................................... 254
Exercise 5.3: Asynchronous Non-Blocking I/O ............................................................................... 257
Exercise 5.4: Text Bundles ............................................................................................................ 268
Exercise 5.5: Web Sockets ............................................................................................................ 273

Exercise 6 – Packaging for Transport.................................................................................... 278
Exercise 6 – Solution ............................................................................................................ 279
Exercise 6.1: Package for Transport .............................................................................................. 279

3

SAP HANA Extended Application Services, Advanced model Development

BEFORE YOU START
System Host: <hostname>
System Instance Number: 00
Desktop User: student
System User ID: WORKSHOP_<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 WORKSHOP_01
All Passwords: HanaRocks2016
XSA Organization: <xsa org>
XSA Development Space: DEV

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_for_SAP_HANA_XS_Advanced_Model
_en.pdf

Source code solutions
All source code solutions and templates for all exercises in this document can be found in the following
webpage.
https://github.com/SAP/com.sap.openSAP.hana5.templates/
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 (or you can use the
bookmark shortcut we have created for you in Google Chrome). You can access the source code for
each exercise by clicking on the appropriate exercise in the navigation bar.
https://github.com/SAP/com.sap.openSAP.hana5.templates/

4

SAP HANA Extended Application Services, Advanced model Development

EXERCISE 1 – HELLO WORLD
Objective
In this first exercise, we will connect to the remote system, run the new project wizard, and then create an
HTML5 module to serve as the application endpoint and proxy all of our services and client-side content.
At the end of this exercise you will be able to connect to your server via web browser and see a Hello World
message.

5

SAP HANA Extended Application Services.1: HTML5 Module . Use File->New->Project from Template 6 Screenshot . Advanced model Development EXERCISE 1 – SOLUTION Exercise 1. https://<hostname>:53075/ User: WORKSHOP_XX where XX is your group number Password: HanaRocks2016 2. We will begin by creating a new project from template. Launch the SAP Web IDE for SAP HANA at the following URL in your web browser.Hello World Explanation 1.

7 . Advanced model Development 3. Enter the project name openSAPHANA5. 4. Press Next.SAP HANA Extended Application Services. Choose Multi-Target Application Project and then press Next.

Your empty project has been created. Press Finish to complete the wizard and generate your new project. Set the Space to DEV (or your system specific development space choosen by your system administrator).SAP HANA Extended Application Services.Then press Next. 8 . Advanced model Development 5. You can optionally enter a description for your new application. 7. 6.

name: web type: html5 path: web requires: . Name the module web.0.1 modules: .SAP HANA Extended Application Services. This not only adds the necessary metadata to the web folder but also maintains the module entry in the project’s mta.0 ID: openSAPHANA5 description: Group 01 version: 0.yaml file within the project root. We need to add openSAPHANA5_XX-uaa (where XX is your group number) as a dependent service/resource to the mta.yaml file. Press Next. Then press Finish. This is because we have user authentication required to access our application.0. Save your file. Advanced model Development 8.name: openSAPHANA5_<group XX>-uaa 9 . Begin by selecting your project and then choosing New -> HTML5 Module 9. Next we need to create the HTML5 module to host and serve out the frontend content. 10. _schema-version: 2. 11.

From a command line type the following to connect to remote XSA server. Advanced model Development Note: if you don’t want to type this code. we recommend that you cut and paste it from this web address https://github.uaa parameters: config_path: .com/SAP/co m.name: openSAPHANA5_<group XX>-uaa type: com.sap.tem plates/blob/master/ex1/ex1 _1 12.hana5. To create the UAA service issue the following command: xs create-service xsuaa space openSAPHANA5_XX-uaa (where XX is your group number) 10 resources: . adding the resource declaration to the MTA descriptor will allow the tools to automatically provision these resources at runtime. But this functionality is not yet provided for UAA services./xs-security. xs login -a https://<hostname>:30030 o <xsa org> -s DEV -u WORKSHOP_<group #> -p HanaRocks2016 –skip-sslvalidation 13.json .openSAP.sap.xs.SAP HANA Extended Application Services. Therefore we have to use the XS command line client tool to perform this step. In future.

templates/bl ob/master/ex1/ex1_2 11 . Advanced model Development 14.The web folder in our project contains the resources that will be served out by this HTML5 module.html with “Hello World” in the resources folder. We are just pointing out content the wizard created already. Note: There is no task to perform in this step. The Add Module wizard already placed a simple index. The HTML5 module is configured via the file xsapp. 15. We can also set authentication and other options. we recommend that you cut and paste it from this web address https://github. "routes": [ ] } Let’s go ahead and change the authenticationMethod to route. In this file we can map the routes to destinations we defined in the mta.SAP HANA Extended Application Services.openSAP. { "welcomeFile": "index. "authenticationMethod": "route".hana5. This HTML5 module manages all HTML/client side UI resources (in the resources folder) and performs the task of reverse proxy for all other internal services.html".sa p. Note: if you don’t want to type this code.com/SAP/com. This way you have a single HTTP endpoint and avoid any CORS issues.json.yaml.

This can be 12 .SAP HANA Extended Application Services.It can take a minute or two for the first build/deploy/run operation to complete. then deploy the service onto the server.Our initial development is done and we are ready to deploy our application onto the XS Advanced server.Switch your browser tab and you should see the authentication prompt for your application. Authentication at the XS level is now done by referencing a user stored. Highlight the web folder and press Run. This will perform a build. Advanced model Development 16. 18. Upon completion you should see that the service status has changed to Running and there is a hyper link to the run logs. Login with the same user credentials you used to log into the SAP Web IDE for SAP HANA (Hint: You might not see this screen if you authentication is still cached in the browser from the login to the SAP Web IDE for SAP HANA itself). If successful it will open a new browser tab to the default page of this web service. 17.

After successful authentication. Advanced model Development configured to be the HANA database or it can be an external user directory.SAP HANA Extended Application Services.html with the Hello World button. 19.Congratulations! You just wrote your first XS Advanced application. you should see your index. 13 . 20.

SAP HANA Extended Application Services. 3. If you do not have a github. Otherwise please open your web browser and navigate to https://github. We use a central Git to store all design time artifacts. please skip ahead to Exercise 1. you only see the projects which have been pulled from Git or which you have created locally in your workspace. In this exercise we will see how we can clone a project from Git to bring it into our local SAP Web IDE for SAP HANA workspace.3 for an alternative soluation.com. you can always skip ahead to Exercise 1. If you do not already have a github. There is no repository browser.3 14 Screenshot . If you already have a github. Therefore when you launch the Web IDE for SAP HANA.2: Clone a Repository from Git With XSA/HDI based development we no longer use the HANA database as the design time repository. please follow the instructions to create and activate your account. Remember: If you do not wish to create an account. Explanation 1. you can alternatively import the project from the file system. please sign in now.com account. 2. If you do not have a github.com account.com account or don’t wish to create one. Advanced model Development Exercise 1.com account and don’t wish to create one.

Advanced model Development 4.SAP HANA Extended Application Services.com/SAP/com.hana5.example This is the example implementation project for this course which you can refer to if you have any problems.sa p. please navigate to this URL: https://github. 5. 15 . Right mouse click on the Workspace and choose Git->Clone Repository. Once you have sucessfully logged into your github account. Return to the SAP Web IDE for SAP HANA.openSAP.

the com.sap. If sucessful.openSAP.sap.exa mple Host: github.e xample project will now appear in your workspace and is connected to the git repository.SAP HANA Extended Application Services. In the Clone Repository dialog. 16 .hana5.openSAP.com/SAP/co m. please use the following values.openSAP. URL: https://github.com password> Remember me: check Press OK.hana5. 7.com Repository Path: /SAP/com.ha na5.example Protocol: https Port: 443 User: <your github.com user or email> Password: <your github. Advanced model Development 6.sap.

Advanced model Development 8. If you have reached this step you can move ahead to Exercise 2. please move onto Exercise 1. Right mouse click on your project and choose 9. 17 . Choose the Space section and then choose DEV as the Development Space (or whatever system specific space your system has configured for you to perform development in). Press Save.SAP HANA Extended Application Services.3. If you were not able to complete it for whatever reason.

example/arc hive/master. Remove the –master portion of the Import to target. Return to the SAP Web IDE for SAP HANA. 4. the com.openSAP.e xample project will now appear in your workspace. 3. Press the OK button to import the template project. 18 Screenshot . If sucessful.sa p.com/SAP/com. Right mouse click on the Workspace and choose Import -> From File System. Advanced model Development Exercise 1.openSAP. Select the file and click Open.hana5.sap. Click the browse button and from the File Open dialog choose the location where you download the file in step 1 of this exercise.SAP HANA Extended Application Services.3: Alternative: Import Project from File System Explanation 1.zip 2.hana5. Download a zip file with the complete project contents from the following location: https://github.

Choose the Space section and then choose DEV as the Development Space (or whatever system specific space your system has configured for you to perform development in). 19 .SAP HANA Extended Application Services. Advanced model Development 5. Press Save. Right mouse click on your project and choose 6.

we will continue to develop our overall application.SAP HANA Extended Application Services. Applications in the HANA/XS Advanced world. are often made up of multiple modules at design time which deploy to separate microservices or database container content. such as database table. schema-less HDI (HANA Deployment Infrastructure) concepts. stored procedures and user defined functions. using the HDB (HANA Database) module. We will then see how we build these database artifacts using the new container-based. We created client side UI application content in the first exercise using the HTML5 module. Advanced model Development EXERCISE 2 –DATABASE ARTIFACT DEVELOPMENT Objective In this exercise. Exercise Description  Database Tables via HDBCDS  Stored Procedures via HDBPROCEDURE  User Defined Functions via HDBFUNCTION  Initial table data load via CSV  Deploy to HANA via HDI 20 . In this exercise we will create database artifacts.

New to HANA in SPS 11 is the HANA Deployment Infrastructure or HDI. All of that information is stored within the container definition. The goal of HDI is to manage database artifacts from design time objects but in a way that allows multiple copies/versions of the same core objects to be used on the same HANA database at the same time. 2. Choose View->Show Hidden Files 21 . XS Advanced based services then only need access to the container and never need to know the actual Schema. The container in turn dynamically generates the Schema. Advanced model Development EXERCISE 2 – SOLUTION Exercise 2. and a password for that database user. a container-specific Database User who owns all objects. HDI introduces the concept of the container as an abstraction of the Schema.1: Database Content Explanation Screenshot 1. or password. technical user.SAP HANA Extended Application Services.

5. Thefore just clear the Namsapce field and press Next. The namespace for database artifacts is optional in HDI and we will choose not to use one. Advanced model Development 3. Then press Next. Begin by selecting your project and then choosing New -> HDB Module 4.SAP HANA Extended Application Services. Name this new module coredb. 22 .

The wizard has created the core-db folder as well as the hdi-container resource and the db module in the mta. You will notice a new folder called core-db which contains a src folder with some files. Advanced model Development 6. Save your changes. Press Finish to complete the creation of the HDB Module. 8. Open the .hdinamespace file and remove the namespace value as shown and change the subfolder value to ignore.yaml file for you. 23 .SAP HANA Extended Application Services. 7.

This configuration will not be used when building from the Web IDE. The .hdinamespace file configures the package namespace for your development objects. As we no longer use the HANA Repository to hold design time objects. 11. This way you can choose any file extensions you wish to use as long as you map them to the correct plug-ins. However it can only have one primary resouce which is the target for all database development objects it will create.SAP HANA Extended Application Services.yaml file. Add the configuation to name your schema OPENSAP_HANA5_XX where XX is your group number. The . this file provides the 24 .An HDB module can also have more than one database resource associated with it. However we will use the default mappings for now.hdiconfig file maps the file extensions to the specific server side activation plug-ins. This requires us to set this resources as the TARGET_CONTAINER in order to describe it as the primary database resource for this module. 10. Later we will add more resources for cross container access. Save the mta. but only when installation from a full MTAR. Advanced model Development 9. There are two configuration files in the root of this folder.The db/src folder is where your actual database development objects belong. You can now add a configuration parameter to the database resource to choose the generated Schema Name upon installation.

Click on the Search HDI Containers button. 14. If you are prompted for your username/password: User: WORKSHOP_XX where XX is your group number Password: HanaRocks2016 15. 13. 12.Go to the SAP HANA Rutnime Tool (HRTT) via the following URL: https://<hostname>:<hrtt_port >/ or use the Tools -> SAP HANA Runtime Tools option from your menu.Select the db module and choose Build->Build.SAP HANA Extended Application Services. 25 . Advanced model Development same service as the folder structure in the Repository used to.You should see a message that you build was sucessful.

SAP HANA Extended Application Services.Search for your container based upon your User Name. Advanced model Development 16. 26 . Then click Connect.You can now see your container in which your database artifacts will be deployed. 17.

the tool will display all the technical information about the container – generated schema name. Advanced model Development 18. 27 .SAP HANA Extended Application Services.If you click the I-icon with the container selected. userss. etc.

Name the folder data. Return to the SAP Web IDE for SAP HANA.SAP HANA Extended Application Services. Now create the hdbcds artifact via New->CDS Artifact to create the core database tables and views in our application. 2. 28 Screenshot . Advanced model Development Exercise 2. Explanation 1. Create a new folder under the src folder by right-clicking it and choosing New>Folder.2: Create Tables & Views via Core Data Services In this exercise you will create a Purchase Order header and item table as well as a view over those two tables using Core Data Services(CDS).

4. Entity Item { 29 . hdbcds is the new file extension replacing hdbdd. } technical configuration { column store.SAP HANA Extended Application Services. type StatusT: String(1). Name the new CDS file PurchaseOrder and press Create.3). Type HistoryT { CREATEDBY : BusinessKey. NETAMOUNT: AmountT. APPROVALSTATUS: StatusT. CHANGEDBY : BusinessKey. PARTNER: BusinessKey. Here is the code for PurchaseOrder. We are creating a simple Purchase Order Header and Item data model. INVOICINGSTATUS: StatusT. CHANGEDAT : SDate.sap. LIFECYCLESTATUS: StatusT.2). }.hdbcds Save the artifact after entering this code.tem plates/blob/master/ex2/ex2 _1 context PurchaseOrder { type BusinessKey : String(10). type SDate : LocalDate. CREATEDAT : SDate. type UnitT: String(3). we recommend that you cut and paste it from this web address https://github. Advanced model Development 3. NOTEID: BusinessKey null. Entity Header { key PURCHASEORDERID: BusinessKey.openSAP. ORDERINGSTATUS: StatusT. type AmountT : Decimal(15. CURRENCY: CurrencyT. The syntax is the same as CDS-based development objects previously. Note: if you don’t want to type this code.PURCHASEORDERID = PURCHASEORDERID. TAXAMOUNT: AmountT. }. type QuantityT : Decimal(13. It contains the table and view definitions. ITEMS: Association[*] to Item on ITEMS.hana5. type CurrencyT : String(5). HISTORY: HistoryT. CONFIRMSTATUS: StatusT.com/SAP/co m. GROSSAMOUNT: AmountT.

UnitT.PURCHASEORDERID = PURCHASEORDERID. 30 context PurchaseOrder { type BusinessKey : String(10). type StatusT: String(1). CURRENCY as "CurrencyCode". QuantityT. HEADER: Association[1] to Header on HEADER. Advanced model Development key PURCHASEORDERID: BusinessKey. QUANTITY: QuantityT. } technical configuration { column store. PRODUCT as "ProductID". type CurrencyT : String(5). and StatusT. DELIVERYDATE: SDate. define view ItemView as SELECT from Item { PURCHASEORDERID as "PurchaseOrderItemId". type AmountT : Decimal(15. NOTEID: BusinessKey null. Let’s look at the syntax you just entered into the hdbcds file in more detail. type UnitT: String(3). 5. GROSSAMOUNT as "Amount". NETAMOUNT as "NetAmount". QUANTITYUNIT as "QuantityUnit".3). create element types for BusinessKey.SAP HANA Extended Application Services. First we need to define some reusable elemental types. HEADER.2). SDate. key PURCHASEORDERITEM: BusinessKey. QUANTITY as "Quantity". AmountT. QUANTITYUNIT: UnitT. DELIVERYDATE as "DeliveryDate1" } with structured privilege check. TAXAMOUNT as "TaxAmount". type SDate : LocalDate. TAXAMOUNT: AmountT. type QuantityT : Decimal(13. Within the PurchaseOrder context. PRODUCT: BusinessKey. }. These will later be used to define the data type of individual columns in our tables. CurrencyT. . NETAMOUNT: AmountT. }. PURCHASEORDERITEM as "ItemPos".PARTNER as "PartnerId". CURRENCY: CurrencyT. GROSSAMOUNT: AmountT.

} technical configuration { column store. CHANGEDAT : SDate. NETAMOUNT: AmountT. TAXAMOUNT: AmountT. }.SAP HANA Extended Application Services. Entity Header { key PURCHASEORDERID: BusinessKey. CHANGEDBY : BusinessKey. We can also create reusable structures with multiple fields. CREATEDAT : SDate. INVOICINGSTATUS: StatusT. Entities will become database tables when activating the hdbcds file. LIFECYCLESTATUS: StatusT. APPROVALSTATUS: StatusT. PARTNER: BusinessKey. The syntax for creating Entities is similar to types. CREATEDAT. CONFIRMSTATUS: StatusT. CHANGEDBY. 31 . 7. GROSSAMOUNT: AmountT. CURRENCY: CurrencyT. HISTORY: HistoryT. and CHANGEDAT fields. }. NOTEID: BusinessKey null. This is useful when the same sets of fields are repeated in multiple tables. 8. ORDERINGSTATUS: StatusT. Create a reusable structure for History – with CREATEDBY. Advanced model Development 6. ITEMS: Association[*] to Item on ITEMS. Type HistoryT { CREATEDBY : BusinessKey. Save your file and build the hdb module again.PURCHASEORDERID = PURCHASEORDERID.

SAP HANA Extended Application Services.Right-click on the PurchaseOrder.Header table and choose Open Definition 32 . Advanced model Development 9. expand the Tables and Views folders and explore the new tables and view 10. Switch over to the SAP HANA Runtime Tools(HRTT) and browse your container.

And you can query the data in these objects. We will see how we can load an initial set of data in the next exercise. Advanced model Development 11. Althought there won’t be any yet.Explore the table definition.SAP HANA Extended Application Services. notice the column names where we used the complex type definition called History 12. 33 .

We will solve this later as well once we setup some roles in our container. even the technical user of the container doesn’t have access because of the structured privilege we placed upon it. 34 . however. Advanced model Development 13.SAP HANA Extended Application Services. If you try to access the data in the view.

3: Create Sequences and Table Data Configuration In this exercise.hdbsequence”. 4. we use a unique order id number as the primary key. Click “OK”. Create a new folder under the src folder by right-clicking it and choosing New->Folder. 2. Therefore we need a sequence to have an auto incrementing unique id generated for us as we insert new data Create a new sequence by right-clicking on the sequences folder and choosing “New”.Header" 35 . Enter the name of the file as “orderId. Name the folder sequences. With the tables we created. 3. Advanced model Development Exercise 2. 0)+1 FROM "PurchaseOrder. Make it dependent upon your header table with the full package id on the front of the header table name.SAP HANA Extended Application Services. Return to the SAP Web IDE for SAP HANA. Explanation Screenshot 1. SEQUENCE "orderId" INCREMENT BY 1 START WITH 200000000 MINVALUE 1 MAXVALUE 2999999999 NO CYCLE RESET BY SELECT IFNULL(MAX(PURCHASEORDERID). you will create a sequence and table data configuration file which will load data into your tables during the deploy process. then “File”. Create a non-cycling sequence within your schema starting from 200000000 and ending with 299999999.

The data load for table requires two files – 1. Advanced model Development Note: if you don’t want to type this code. "NOTEID".Header". An csv (comma separated) file which holds the data you want to load.hana5. we recommend that you cut and paste it from this web address 36 { "format_version": 1. Don’t forget to save the file afterwards. "PARTNER".hdbtabledata in the data folder and enter this text into it. We also have the hdbtabledata development object. 2. "file_name": "header. "has_header": false. "source_data": { “data_type": "CSV". You may want to deliver an initial set of data within a table – particular a configuration table.SAP HANA Extended Application Services. In this exercises we will learn how to create automatic data load configuration and the accompanying CSV files for just such a situation.csv".template s/blob/master/ex2/ex2_2 Save your sequence file. "import_settings": { "import_columns": [ "PURCHASEORDERID".com/SAP/com. "imports": [{ "target_table": "PurchaseOrder. "type_config": { "delimiter": ". Although the syntax of this object is new. the purpose is the same – to allow the loading of initial data from CSV files it target tables during their creation. "CURRENCY". "dialect": "HANA". This is the replacement for the old hdbti development object. 5. "NETAMOUNT". "GROSSAMOUNT"." } }.s ap. 6.openSAP. Note: if you don’t want to type this code. An hdbtabledata file which specifies the target table for a source csv file. Create a file named Purchase. . we recommend that you cut and paste it from this web address https://github.

csv"." } }.SAP HANA Extended Application Services. "CURRENCY": 5. "has_header": false. "PARTNER": 7.openSAP. "TAXAMOUNT". "QUANTITY". "file_name": "item.hana5. "LIFECYCLESTATUS". "TAXAMOUNT": 11. "PURCHASEORDERITEM": 2. "NOTEID": 4. { "target_table": "PurchaseOrder. "INVOICINGSTATUS": 16 } }. "APPROVALSTATUS". "QUANTITYUNIT" ] }.Item". "NETAMOUNT": 7. "PRODUCT". "PRODUCT": 3. "type_config": { "delimiter": ". "source_data": { "data_type": "CSV". "import_settings": { "import_columns": [ "PURCHASEORDERID". "APPROVALSTATUS": 13. "INVOICINGSTATUS"] }. "NOTEID". "ORDERINGSTATUS": 15. "CONFIRMSTATUS". "CURRENCY". "CONFIRMSTATUS": 14.com/SAP/com. "NETAMOUNT". "LIFECYCLESTATUS": 12.s ap. "column_mappings": { "PURCHASEORDERID": 1. "CURRENCY": 8. "GROSSAMOUNT": 6. "NOTEID": 6. "column_mappings": { "PURCHASEORDERID": 1. 37 .templates/ blob/master/ex2/ex2_3 "TAXAMOUNT". "GROSSAMOUNT": 9. "PURCHASEORDERITEM". "GROSSAMOUNT". "NETAMOUNT": 10. "ORDERINGSTATUS". "dialect": "HANA". Advanced model Development https://github.

20121204 0500000000.20121204 0500000001.20121204 0500000000.csv and save it.16.HT1100.EUR.88.1116.1407.956.9..34.1.2.22.38.544.2111.EA.3.0000000033.2.98.I.0000000030.EUR.3.92.0000000070.11.3140.com/SAP/com.938.USD.1674. We need some CSV files to hold some initial test data to be loaded by the hdbtabledata configuration file.52.3736.179..20120101.EA.EA.96.0000000040.20121204 0500000001..EUR.EA.363.178.64..0000000080.0000000033.22.28.213.0000000050. 0500000000.2275.EA.34.EA.openSAP.EA. Note: if you don’t want to type this code.N.78. And data for the item table named item.82.EUR.71.EA.HT1000.20121204 0500000001.s ap. Note: if you don’t want to type this code. we recommend that you cut and paste it from this web address https://github.HT1091.HT1000.33.1994.HT2026.USD.0100000000.EUR.s ap.0000000040.4.2.HT1000.11113.20120102..HT6100.28.181.EUR.2868.EA.. I.. "QUANTITYUNIT": 10 } }] } 7.178.96.0000000100.10498.16.47.33.EUR.20121204 0500000000.596.0000000033.6.2.0000000020.47.14.20121204 0500000000.EA.1116.N.1912.templates/ blob/master/ex2/ex2_4 8..EA.2.92.20120101.hana5.0000000033.EUR.213.79.0000000010.EA.28.EA.2..hana5.HT6100.73.USD.5.I..9 000000001.20121204 0500000001.0000000050.3412.9.2275.HT2026.61.0000000090.HT1000.20120102. Advanced model Development "TAXAMOUNT": 8.csv.7.HT6100.HT1002.94.com/SAP/com..I. we recommend that you cut and paste it from this web address https://github.I 0500000001.20121204 .22.2.29.1.2.6.9 000000001.59..EUR.82. Don’t forget to save.267.20121204 0500000000.69.12493..HT1091.20121204 0500000000.13224. "QUANTITY": 9.EA.88.20121204 0500000000..363.USD.35.64.88.USD.HT1100.I.20121204 0500000000.EUR.28.I Enter this data into a file named header.2.openSAP.1137.52.EUR.61.I.8.22.SAP HANA Extended Application Services.3.HT1091.0000000020.templates/ blob/master/ex2/ex2_5 38 0500000000.0000000030.1912.20121204 0500000001.0000000060.92.179.EUR.EA.0100000002.938.88.0000000010.20121204 0500000000.8.2..99.

3140.HT1002.You will notice that your table now has some data.24. Advanced model Development 0500000001.0000000080..06.2.7.6..3736.20121204 0500000001.24. 39 ..97.USD.6.94.SAP HANA Extended Application Services..EA.51.89.596.Item table as well.3.320.20121204 0500000001.USD.20121204 9.7.0000000060.596. Return to the SAP HANA Runtime Tools (HRTT) and right-click on the PurchaseOrder.HT1100.20121204 0500000001.HT1100.3.269.51.3140.USD.2.6.3.Repeat these steps to view the data in the PurchaseOrder.HT1002.107.0000000070.0000000100.09.EA.20121204 0500000001.3736.Header table and choose Open Content.EA.17.USD.0000000090..USD.EA.EA. Save all files and build your hdb module again.269. 11.320.HT2026.94. 10.6.

Return to the SAP Web IDE for SAP HANA. 3.4: Create Synonym. However if you want to allow access via other database users (for use cases such as external reporting tools). We also need synonyms now to access any table or view outside of our container. All access to our HDI database objects from XSA is done automatically by the HDI container technical user. Click “Save”. Structured Privilege & Role In this exercise. we will also need a database role.hdbsynonym in the data folder and add a synonym named DUMMY for DUMMY as shown. Return to the SAP Web IDE for SAP HANA and create another folder called roles by right-clicking on the src folder and choosing New->Folder. 2.SAP HANA Extended Application Services. Therefore we will create an hdbsynonym to allow us to access the dummy view. Create a file called sys. you must create a database role. Explanation 1. 40 Screenshot . Advanced model Development Exercise 2. Also if you want to grant additional privileges to the technical user (such as the structured privleges for our view). you will create a structured privilege and role and assign it to you user.

"EXECUTE". "UPDATE". "CREATE TEMPORARY TABLE". we recommend that you cut and paste it from this web address https://github. Note: if you don’t want to type this code.hana5. Now create a role named admin. "INSERT".com/SAP/com. STRUCTURED PRIVILEGE "PO_VIEW_PRIVILEGE" FOR SELECT ON "PurchaseOrder.hana5.openSAP. "SELECT".hdbrole and enter this code.templates/ blob/master/ex2/ex2_7 { "role":{ "name": "admin".SAP HANA Extended Application Services. 5.ItemView" WHERE "CurrencyCode" = 'EUR' Enter this code into the file PurchaseOrder.com/SAP/com. "schema_privileges": [{ "privileges": ["SELECT METADATA". First we need to create a structured privilege. Don’t forget to save. "SELECT CDS METADATA". This is closely related to the analytic privilege and allows us to perform instance filtering for our CDS view we created earlier.s ap. we recommend that you cut and paste it from this web address https://github.template s/blob/master/ex2/ex2_6 This will limit the access to our view to only allow users with this privilege to see items for Euros.openSAP. "DELETE". "schema_analytic_privileges": [ { "privileges":[ "PO_VIEW_PRIVILEGE" ] } ] } } 41 . Advanced model Development 4.hdbstructured privilege and save. Note: if you don’t want to type this code. "TRIGGER" ] }].s ap.

hdbrole Enter the following text.openSAP. Save all files and build the hdb module. 9.templates/ blob/master/ex2/ex2_8 7.hdbrole we created in the previous step to our technical user automatically upon build. Return to the HRTT. This will grant the admin. Inside this folder create a file named default_access_role. Therefore we need to create a role with a special name – default_access_role.hana5. Advanced model Development 6. We want this role to be automatically granted to our technical user. they need the database role granted to their user.s ap.SAP HANA Extended Application Services.com/SAP/com. { "role":{ "name": "default_access_role". 8. we recommend that you cut and paste it from this web address https://github. Try to access the data in the view again and it should be sucessful this time. In order to access the structure privilege based view or for a database user other than the technical user to access any of the catalog objects. 42 } . "schema_roles": [{ "names": ["admin"] }] } Create a folder named defaults in src. Note: if you don’t want to type this code.

templates/ blob/master/ex2/ex2_9 Be sure replace the placeholder for group number.com/docs/DOC-41576 Explanation Screenshot 1. here: http://scn.\"password\":\"<Password>\".Driver\".\"user\":\"<user>\". Return to the Command Prompt and the XS client command line tool we used in exercise one.com/SAP/com.openSAP. A User Provided Service allows our modules to connect to existing database schemas which aren’t managed by HDI.sap. 43 .db. user.jdbc.5: Non-Container Schemas. User Provided Services & Synonyms In this exercise. if it doesn’t exist already. instance number.sap. Advanced model Development Exercise 2. you can reference the solution web page at https://github. \"schema\" : \"SFLIGHT\" }" If you do not wish to type this code. \"driver\":\"com. You can find more information on loading SFLIGHT into your system.\"port\":\"3<Instance Number><15|13>\". and password. This exercise requires that you have the SFLIGHT catalog schema installed in your system and a database user who has access to this schema. hostname.\"tags\":[\"hana\"] . xs cups CROSS_SCHEMA_SFLIGHT_<group number> -p "{\"host\":\"<hostname>\". service port (15 for for single container systems and 13 for MDC systems using the sysem DB). This would be the case for replicated schemas or ERP ABAP schemas for instance.SAP HANA Extended Application Services. we will create a synonym in order to access a table within another container. 2.s ap.hana5. Next you will need to create the User Provided Service manually from the command line.

You should now see something like the following. Advanced model Development 3.s ap.SAP HANA Extended Application Services. 4. Modify the requires section of the core-db module in the mta.hana5. you can reference the solution web page at https://github.ymal file as shown.templates/ blob/master/ex2/ex2_10 44 . 5.yaml file.com/SAP/com. Switch over to the SAP Web IDE for SAP HANA and open the mta.openSAP. If you do not wish to type this code.

If you do not wish to type this code.openSAP.name: hdi-container properties: hdi-container-name: ${service-name} type: com.name: openSAPHANA5_00-uaa type: com.sap.hana5. Make sure to substitue your group number where applicable.s ap. Modify the resources section of the mta file as shown. The completed code should look very similar to the following.name: web type: html5 path: web requires: .name: hdi-container properties: TARGET_CONTAINER: ~{hdi-container-name} .name: core-db type: hdb path: core-db requires: . Advanced model Development 6.xs.name: openSAPHANA5_00-uaa .sap.0 ID: openSAPHANA5 description: Group 00 version: 0.hdi-container parameters: config: 45 .name: CrossSchemaService group: SERVICE_REPLACEMENTS properties: key: hdi-sflight-service service: ~{sflight-service-name} resources: .templates/ blob/master/ex2/ex2_11 7./xs-security.com/SAP/com.1 modules: . you can reference the solution web page at https://github.xs.json .0.SAP HANA Extended Application Services. _schema-version: 2.uaa parameters: config_path: .0.

name: CrossSchemaService type: org. you can reference the solution web page at https://github. Create a new folder called cfg under the core-db folder. "privileges_with_grant_option":["SELECT".hana5. Enter the following code.cloudfoundry. "application_user" : { "schema_privileges":[ { . Advanced model Development schema: OPENSAP_HANA5_00 . "SELECT METADATA"] } ] }. 10.openSAP. If you do not wish to type this code.s ap. Create a new file in the cfg folder called SFLIGHT.hdbgrants by rightclicking on the cfg folder and choosing New->File 11.com/SAP/com. 9. Click Save.existing-service parameters: service-name: CROSS_SCHEMA_SFLIGHT_00 properties: sflight-service-name: ${service-name} 8.templates/ blob/master/ex2/ex2_12 46 { "hdi-sflight-service": { "object_owner" : { "schema_privileges":[ { "reference":"SFLIGHT".SAP HANA Extended Application Services.

"privileges_with_grant_option":["SELECT". 14.SAP HANA Extended Application Services. 15. 16. Click Save 13. Click Save 47 . "SELECT METADATA"] } ] } } } 12. Click the + button to add new entries. Go to the data folder within the src folder and create a new file called sflight. Advanced model Development "reference":"SFLIGHT". Add the following entries as shown.hdbsynonym by rightclicking on the data folder and choosing New->File.

Create another CDS artifact in the data folder by rightclicking on the data folder and choosing New->CDS Artifact.SAP HANA Extended Application Services. Insert the following code as shown If you do not wish to type this code.templates/ blob/master/ex2/ex2_13 48 . you can reference the solution web page at https://github.openSAP.hana5.com/SAP/com.com/SAP/com. Check to make sure the build is sucessful. Select the hdb module and choose Build->Build. Name it FLIGHT. you can reference the solution web page at https://github. 19.s ap.openSAP. If you do not wish to type this code. enter the following code for the context. 18. Advanced model Development 17. Below the USING statements.s ap.templates/ blob/master/ex2/ex2_13 20.hana5.

com/SAP/com. enter the following code for the SflightExt view. insert the following code for the view. If you do not wish to type this code.com/SAP/com.templates/ blob/master/ex2/ex2_13 23.SAP HANA Extended Application Services. using SBOOK. you can reference the solution web page at define view SflightView as SELECT from FLIGHTTBL mixin { 49 .hana5. context FLIGHT{ If you do not wish to type this code.templates/ blob/master/ex2/ex2_13 22. you can reference the solution web page at https://github.openSAP. If you do not wish to type this code. The completed code should be very similar to the following. Advanced model Development 21.hana5.s ap.s ap. Within the FLIGHT context. you can reference the solution web page at https://github. using SFLIGHT as FLIGHTTBL. After the SflightView definition.openSAP.

CONNID as "ConnectionId". "Bookings".ConnectionId and SBOOKLink.templates/ blob/master/ex2/ex2_13 SBOOKLink: Association[*] to SBOOK on SBOOKLink. 50 . CURRENCY as "Currency".CARRID = $projection.CUSTTYPE as "CustomerType". "Bookings".CarrierId and SBOOKLink. "PlaneType".SAP HANA Extended Application Services. 24. "CarrierId".PASSNAME as "PassengerName" } with structured privilege check. Advanced model Development https://github.CUSTOMID as "CustomerId".openSAP.CONNID = $projection. }.hana5. } into { MANDT as "Client".MANDT = $projection.BOOKID as "BookingId". "Bookings".com/SAP/com. "Price".s ap.Client and SBOOKLink. "FlightDate". Click Save.FlightDate.FLDATE = $projection. CARRID as "CarrierId". "ConnectionId". FLDATE as "FlightDate". SBOOKLink as "Bookings" }. PLANETYPE as "PlaneType". PRICE as "Price". "Bookings". define view SflightExt as select from SflightView{ "Client". "Currency".

Open the admin. Click Save.hdbstructured privilege by right-clicking on the roles folder and choosing New->File.s ap. Under the roles folder.hdbrole file in the roles folder and add the new structured privilege as shown. 26.hana5. 28.com/SAP/com.SAP HANA Extended Application Services. create a new structured privilege called SFLIGHT_PRIV.templates/ blob/master/ex2/ex2_14 27. you can reference the solution web page at STRUCTURED PRIVILEGE "FLIGHT_VIEW_PRIVILEGE" FOR SELECT ON "FLIGHT. Enter the following code as shown. If you do not wish to type this code. Advanced model Development 25.openSAP.SflightExt" WHERE "Client" = '001' https://github. 51 .

Click Save. 32.SflightExt view in the Views folder and choose Open Content. Select the db module and choose Build->Build. The results are shown. 52 . Advanced model Development 29. 30. 31. Rightclick on the FLIGHT.SAP HANA Extended Application Services. Switch over to the SAP HANA Runtime Tools(HRTT).

Right mouse click on the project and choose New->HDB Module 2. However we also want user data but that should be a complete separate HDI container.6: Cross Container Services & Synonyms XSA embraces the concepts of a micro-service architecture. In this exercise we will create a second HDB module and HDI container service and configure access and synonyms between the two.SAP HANA Extended Application Services. This is true also of the database services. So far we have purchase order data in our core-db module. Explanation Screenshot 1. Advanced model Development Exercise 2. 53 . We will begin by creating a second HDB module for our User table. Then press Finish. Name this new module userdb. This means that different parts of the same overall application might be separated into separate services.

54 . Similiar to the SFLIGHT service from the last exericse we will also configure synonym access to the user container from our core container.SAP HANA Extended Application Services. Let’s change the name of the container in the resources section to user-container and the property name to usercontainer-name.hdinamespace file and remove the namespace value as shown and change the subfolder value to ignore. You can now add a requires dependency in the core-db module to the user-container## resource as well. 6. 5. Open the . You will notice a new folder called user-db which contains a src folder with some files.yaml file for you. The wizard has created the user-db folder as well as the hdi-container resource and the db module in the mta. Make similiar adjustments to the user-db module definition itself to use the new name. 4. Save your changes. Advanced model Development 3.

name: user-db type: hdb path: user-db requires: .sap.name: core-db type: hdb path: core-db requires: .name: web type: html5 path: web requires: .0 ID: openSAPHANA5 description: Group 00 version: 0.name: openSAPHANA5_00-uaa type: com.0. _schema-version: 2. 8.0.yaml file.1 modules: .yaml should now look something like this (adjusting for your group number). The compelte mta.name: user-container properties: TARGET_CONTAINER: ~{user-container-name} resources: .xs.name: hdi-container properties: TARGET_CONTAINER: ~{hdi-container-name} .name: CrossSchemaService group: SERVICE_REPLACEMENTS properties: key: hdi-sflight-service service: ~{sflight-service-name} .name: openSAPHANA5_00-uaa . Save the mta.uaa parameters: 55 . Advanced model Development 7. An HDB module can also have more than one database resource associated with it.SAP HANA Extended Application Services. However it can only have one primary resouce which is the target for all database development objects it will create.name: user-container group: SERVICE_REPLACEMENTS properties: key: hdi-user-service service: ~{user-container-name} .

Advanced model Development config_path: .sap. Download src./xs-security. roles.hdi-container parameters: config: schema: OPENSAP_HANA5_USER_00 9.zip from: https://github.hdi-container parameters: config: schema: OPENSAP_HANA5_00 .zip Right mouse click on user-db and choose Import -> From File System.json .existing-service parameters: service-name: CROSS_SCHEMA_SFLIGHT_00 properties: sflight-service-name: ${service-name} .zip from the location where you just saved it on your local machine.xs.name: user-container properties: user-container-name: ${service-name} type: com.openSAP.xs.hana5.sap. etc in the user-db module. Click Browse and chose src.com/SAP/com.s ap. Keep other values at their default and press OK.SAP HANA Extended Application Services.template s/raw/master/ex2/userdb/src. However to save time we will upload a template implementation of these objects.name: hdi-container properties: hdi-container-name: ${service-name} type: com. 56 . We could follow similiar steps to create hdbcds. sequences.name: CrossSchemaService type: org.cloudfoundry.

SAP HANA Extended Application Services. The import loaded many files into user-db/src. 13.hdbcds (with the UserData. 11. You will see this message – which is fine. You should see a message that you build was sucessful. 57 .User entity) and the user.hdbrole. Select the user-db module and choose Build->Build. Advanced model Development 10. Just press OK. but we will be most interested in the UserData. 12.

Now we want to extend access to the user-db container to our original coredb container.openSAP.SAP HANA Extended Application Services. Advanced model Development 14.s ap.hdbrole from the user-db module to grant access to user database content to the technical user of the core-db module.hana5. Enter the following code.com/SAP/com. you can reference the solution web page at https://github. "application_user": { "container_roles":["user"] } } If you do not wish to type this code. { "hdi-user-service": { "object_owner": { "container_roles":["user"] }. Create a new file in the cfg folder of core-db called user.hdbgrants by rightclicking on the cfg folder and choosing New->File 15.templates/ blob/master/ex2/ex2_15 58 } . This is use the user.

Cut and paste sflight.hdbsynonym from the data folder to the new synonyms folder for better organization. so lets create a folder in core-db/src called synonyms. Go to the synonyms folder within the src folder and create a new file called user. Click the + button to add new entries.hdbsynonym by rightclicking on the synonyms folder and choosing New>File. Add the following entries as shown. 18. 17. We are starting to get several synonym files.hdbsynonym and sys.SAP HANA Extended Application Services. 59 . Advanced model Development 16.

Notice we didn’t enter a schema name. That’s because the schema is generated for the foregin container.hdbsynonymtemplate. Select the core-hdb module and choose Build->Build. 21. Save all files. Advanced model Development 19.SAP HANA Extended Application Services. Check to make sure the build is successful. 20. 60 .yaml which will be replaced at build with the actual container name. Here we use the service replacement name configured in the mta. Therefore we also need to create a file named user.

zip from the Download folder of your local client machine. we want to import a larger database module than we care to create by hand.openSAP. Keep all other parameters the same.zip from from: https://github.SAP HANA Extended Application Services.com/SAP/com. Press OK. Advanced model Development Exercise 2. sap. 2) Choose the file data.7 Creating a Graphical Calculation View with a Dimension data type Explanation Screenshot 1) Before we start creating Calculation views.zip Right mouse click on the core-db/src/ folder and choose Import -> From File System. 61 . Download the data. Confirm that it is OK to overwrite the existing files.hana5.templa tes/raw/master/ex2/coredb/data.

5) Similar to the run activity of the web module earlier. 4) Now that we have our database development objects. Select the core-db folder and choose Build -> Build.SAP HANA Extended Application Services.csv twice in our data folder.csv and item. you should see that the build completed successfully. Advanced model Development 3) We now have the header. the status of the build will be displayed in a window in the lower right side of the IDE. 62 .hdbtabledata file in the data folder becuase its duplicated as well. Delete them from the data folder as they are also in the data/loads folder. we are ready to build the module which will create them in the HANA database. Also delete Purchase. If everything worked correctly.

right click and choose “New”. 7) Now we are ready to create our calculation views. 63 . then “Folder”. From the core-db/src folder. Advanced model Development 6) You can explore some of the new tables and their content that have been imported via the HRTT tool.SAP HANA Extended Application Services. This is esentially the same data model as SHINE (SAP HANA Interactive Education).

This will require joining the products.democontent. Our core-db module currently doesn’t use namespaces.SAP HANA Extended Application Services. businessPartner. Create a file named .epm.hdinamespace in the src/models folder. Therefore we will need to re-activate namespaces for just the models folder. create a new calculation view based upon the expanded information for the products.models". Advanced model Development 8) Enter the name of the folder as “models” and click “OK”. 10) In the models sub-folder of your project. Calculation View building fails under certain conditions when no namespace is used. Right mouse click on the models package. texts. "subfolder": "ignore" } . 9) Due to a current bug in SPS 12 (soon to be fixed). choose New -> Calculation View 64 { "name": "sap.hana. and address tables. Enter this text into the file.

Click “Create”. A DIMENSON Calculation View will be very similar to the older Attribute View – A basic join with no aggregation. MD. In order to do so we have to create a join node for each join criteria. 12) We want to join several tables from our project. 65 . Advanced model Development 11) Enter the name as PRODUCTS and a Label of Products View. Start by creating a Join Node pressing the Create Join button.Addresses and Util.BusinessPartner.Products. Choose DIMENSION as the data category. MD.Texts (twice). Ultimately we will join MD.SAP HANA Extended Application Services.

66 . 15) Press the Plus button next to the node to add tables/views to the join node. 14) Click on the node and rename it to Product_BP. Advanced model Development 13) As we have several joins to add drag this new join node down near the bottom of the design window.SAP HANA Extended Application Services.

17) Repeat the process and add MD.Products to the node.SAP HANA Extended Application Services. 67 .BusinessPartner to the node. Advanced model Development 16) Add MD.

NAMEID. Select PRODUCTID. Drag and drop to connect the two columns in the Join Definition. CATEGORY. COMPANYNAME. Advanced model Development 18) We now want to create a join between the two tables on the SUPPLIER. PRICE. DESCID.SAP HANA Extended Application Services.ADDRESSID and then choose Add To Output. 19) Switch to the Mapping tab. CURRENCY.PARTNERID to the PARTNERID column. We can then select which columns we want from this part of the join. 68 .and ADDRESES. TYPECODE. PARTNERID.

21) Repeat the process of adding a Join Node.SAP HANA Extended Application Services. Advanced model Development 20) Optionally. 69 . For example you might change CATEGORY to ProductCategory. Name this new Join Node Address and connect the output Product_BP to this new join node. you can change the name of a column as it becomes part of the view.

23) Create a join between the ADDRESSES_ADDRESSID of the previous join node output and the ADDRESSID column of the MD.SAP HANA Extended Application Services. Advanced model Development 22) Add the MD. 70 .Addresses table to this join node.Addresses table.

SAP HANA Extended Application Services. Select all columns from the Product_BP node except ADDRESSES_ADDRESSID . STREET. Advanced model Development 24) Repeat the process of adding columns to the output. BUILDING. 71 . From The MD. Name this new Join Node Product_Name and connect the output Address to this new join node. COUNTRY. POSTALCODE. and REGION. 25) Repeat the process of adding a Join Node.Addresses table select CITY.

SAP HANA Extended Application Services. 27) Create a join between the NAMEID of the previous join node output and the TEXTID column of the Util. change the Join Type to Text Join and the Language Column to LANGUAGE. 72 . 28) In the Join Properties window. Advanced model Development 26) Add the Util.Texts table to this join node.Texts table.

SAP HANA Extended Application Services. Name this new Join Node Product_Desc and connect the output Product_Name to this new join node. 73 .Texts table select TEXT but change the name of the TEXT column in the output to ProductName . Select all columns from the Address node except NAMEID. Advanced model Development 29) Repeat the process of adding columns to the output via the mapping tab. From the Util. 30) Repeat the process of adding a Join Node.

change the Join Type to Text Join and the Language Column to LANGUAGE. 74 . Advanced model Development 31) Add the Util.Texts table.Texts table to this join node. 33) In the Join Properties window.SAP HANA Extended Application Services. 32) Create a join between the DESCID of the previous join node output and the TEXTID column of the Util.

75 .SAP HANA Extended Application Services.Texts table select TEXT but change the name of the TEXT column in the output to ProductDesc . Advanced model Development 34) Repeat the process of adding columns to the output via the mapping tab. 35) Connect the output of the Product_Desc node to the Projection node at the top of the design window. Select all columns from the Product_Name node except DESCID. From the Util.

Select the Key column for PRODUCTID. change the Apply Privileges to the blank value. 39) Save your model 76 . Advanced model Development 36) In the Projection node and Mapping tab. press the Auto Map by Name button. 38) In the View Properties tab. 37) Select the Semantics node and choose the Columns tab.SAP HANA Extended Application Services.

Your container will now have an entry in the Column Views folder for this new Calculation View.SAP HANA Extended Application Services. 41) For an initial test make sure your output looks similar to the following: 77 . Advanced model Development 40) Build the core-db module and then return to the HRTT tool.

Because we have various currency based amounts in our source data. 78 Screenshot . in your models folder. Set the Data Category to CUBE and choose With Star Join. Using the same steps as the previous part of the exercise.8: Creating a Calculation View with a Cube data type and Star Join Explanation 1) Now we will create another Calculation view – but one which uses the Cube data type and therefore aggregation of the results. Advanced model Development Exercise 2. create a new Calculation View 2) Name your new view PURCHASE_ORDERS. It will combine purchase order table data with the product view we created in the previous step. we will also create a calculated column which contains a currency conversion. This will create a view very similar in capabilities to the older Analytical View.SAP HANA Extended Application Services.

SAP HANA Extended Application Services. Add the PO. Advanced model Development 3) Insert a Join Node into the Scenario. 79 .Item tables to this Join Node.Header and PO.

80 . add the columns HISTORY.. Advanced model Development 4) Create an inner join between PURCHASEORDERID from the header table to the PURCHASEORDERID column of the item table and set the cardinality as 1.CHANGEDAT from the Header table and the PURCHASEORDERID. PRODUCT. 5) Using the Mapping tab. PURCHASEORDERITEM.SAP HANA Extended Application Services. CURRENCY.PRODUCTID. and GROSSAMOUNT columns from the Item table.n.

Search for and select the PRODUCTS view from the previous part of the exercise to insert it into the Join of your new view. 7) Create a join on the PRODUCT_PRODUCTID to the PRODUCTID column. Advanced model Development 6) Connect the output of the Join to the Star Join node. 81 . Press the plus button next to this Star Join node.SAP HANA Extended Application Services.

SAP HANA Extended Application Services. create an input parameter named IP_O_TARGET_CURRENC Y. 9) Configure as shown with type NVARCHAR length 3 with a Semantic type of Currency. 82 . Advanced model Development 8) From the Parameters tab. It should be mandatory and have a default value of USD.

but please double check). Add GROSSAMOUNT a second time and change the column name to OriginalGrossAmount 11) Navigate to the Semantics node and then the Columns tab. Set the GrossAmount and OriginalGrossAmt as measures and all of others as attrbutes. select all the columns of the Star Join node and add them to the output. Advanced model Development 10) From the Mapping tab. (They may already be defaulting into the correct values.SAP HANA Extended Application Services. 12) Select the GrossAmount measure and chose Assign Semantics 13) For the Semantic Type choose Amount with Currency Code 83 .

SAP HANA Extended Application Services. 84 . change the Apply Privileges to the blank value. Advanced model Development 14) Configure the Currency Conversion as shown in the following Screen Shots 15) In the View Properties tab.

Advanced model Development 16) Save your View. 18) You should see output similar to this. It is only test data to show a conversion takes place. Exchange rates are not necessarily accurate in this system. Your container will now have an entry in the Column Views folder for this new Calculation View. In particular check the values of the GROSSAMOUNT and OriginalGrossAmt Columns.SAP HANA Extended Application Services. 85 . therefore those would be the only records with different values in the OriginalGrossAmt column. In this workshop system exchange rates have only been maintained for USD<>EUR. 17) Build the hdb module and then return to the HRTT tool.

ORDER_RANK INTEGER ) LANGUAGE SQLSCRIPT AS BEGIN /***************************** Write your function logic *****************************/ return SELECT company_name. ORDERS INTEGER.sap.9: Creating the Replacement for the Scripted Calculation View Explanation Screenshot 1) Within HDI. Begin by creating a new folder called “functions”. order_rank from( select 86 . Advanced model Development Exercise 2.SAP HANA Extended Application Services. Instead now we will create a SQLScript Table Function and then wrap that in a Graphical Calculation View. In this exercise we want to create such a combination of scripted logic and Calculation view that will select Sales details and ranks. orders. REGION NVARCHAR(4). IP_REGION NVARCHAR(4)) RETURNS table ( COMPANY_NAME NVARCHAR(80).com/SAP/com . we recommend that you cut and paste it from this web address https://github. sales_rank. sales. Then create a new Function named SALESORDER_RANKING_ AND_DISCOUNT_SQL in the functions folder.openSAP. IP_TO_DATE DATE. Input the following code into this function. SALES DECIMAL(18. SALES_RANK INTEGER. there is no such thing as a Scripted Calculation Views.templ ates/blob/master/ex2/ex2_1 6 FUNCTION "SALESORDER_RANKING_AND_DISCOUNT_SQL" (IP_FR_DATE DATE.2). Note: if you don’t want to type this code. region.hana5.

Item" T1 on T0."SALESORDERID" inner join "MD."REGION" = :IP_REGION group by T2."COMPANYNAME"."DELIVERYDATE" from "SO."COMPANYNAME" as COMPANY_NAME."SALESORDERID" = T1. 87 ."REGION" as REGION."NETAMOUNT") as SALES. T3."SALESORDERID") desc ) as order_rank --T1. dense_rank() over ( order by count(T0."PARTNERID" inner join "MD. T2. T3."REGION" order by sales_rank.SAP HANA Extended Application Services. count(T0."DELIVERYDATE") between :IP_FR_DATE and :IP_TO_DATE and T3. END 2) Save your function and then perform a build on the coredb module."PARTNER.Header" T0 inner join "SO."COMPANYNAME" ) where sales_rank < 11."NETAMOUNT") desc ) as sales_rank. Advanced model Development T2.PARTNERID" = T2. sum(T1. 3) Now from the src/models folder create a new Calculation view named SALESORDER_RANKING_ AND_DISCOUNT of type DIMENSION."SALESORDERID") as ORDERS.ADDRESSID" = T3. dense_rank() over ( order by sum(T1."ADDRESSID" where TO_DATE(T1.BusinessPartner" T2 on T0.Addresses" T3 on T2."ADDRESSES.

SAP HANA Extended Application Services. Advanced model Development 4) In the projection node. click the plus and add the SALESORDER_RANKING_ AND_DISCOUNT_SQL function 5) In the Mapping. add all the columns to the Output 6) Go to the Parameters tab and press the Manage Parameter Mapping button 88 .

89 . Advanced model Development 7) Choose the Auto Map button. 8) In the View Properties of the Semantics change the Apply Privileges to the blank value. This will generate matching Input Parameters in your view for all the input parameters exposed by the SQLScript Function. Choose Open Content. 10) Build the hdb module and then return to the HRTT tool. 9) Save your View.SAP HANA Extended Application Services. Your container will now have an entry in the Column Views folder for this new Calculation View.

enter January 1st 2012. In the To Date. 12) The output values will then be displayed 90 . In the Region use the value AMER. use the current date. Press F8 to execute. Advanced model Development 11) In the From Date.SAP HANA Extended Application Services.

We will … - Create an HDB Procedure “get_po_header_data” Add two implicit SELECT statements to the procedure Call the procedure Explanation Screenshot 1. Click “Create” 91 . Enter the name of the procedure as “get_po_header_data”.1: Creating Stored Procedures In this exercise we will create a small procedure “get_po_header_data” with two implicit SELECT queries. Begin by creating a new folder called “procedures”.5. 2. Right click on the “procedures” folder and choose “New”. then “Procedure”. Advanced model Development Exercise 2.SAP HANA Extended Application Services.5: Leveraging SQLScript in Stored Procedures & User Defined Functions Exercise 2.

END 6. 5. 92 . SELECT COUNT(*) AS CHANGE_CNT.CHANGEDBY.Item" WHERE "PRODUCT. Remove the :: from the front of the get_po_header_data procedure name.hana5. you can reference the solution web page at https://github. Save the procedure. Advanced model Development 3. insert the SELECT statements as shown.EMPLOYEEID".PRODUCTID" IS NOT NULL) GROUP BY "HISTORY.openSAP.SAP HANA Extended Application Services.CREATEDBY.CREATEDBY.templates/ blob/master/ex2/ex2_17 PROCEDURE "get_po_header_data" ( ) LANGUAGE SQLSCRIPT SQL SECURITY INVOKER --DEFAULT SCHEMA <default_schema_name> READS SQL DATA AS BEGIN SELECT COUNT(*) AS CREATE_CNT.Header" WHERE PURCHASEORDERID IN ( SELECT PURCHASEORDERID FROM "PO.Header" WHERE PURCHASEORDERID IN ( SELECT PURCHASEORDERID FROM "PO.CHANGEDBY.EMPLOYEEID" FROM "PO. The editor will then be shown.PRODUCTID" IS NOT NULL) GROUP BY "HISTORY. 4. These are implicit select statements whose results sets are passed to the caller.EMPLOYEEID".s ap. Between the BEGIN and END statements.com/SAP/com.EMPLOYEEID" FROM "PO. The completed code should look similar to this. If you do not wish to type this code. "HISTORY.Item" WHERE "PRODUCT. "HISTORY.

https://<hostname>:<hrtt_port > Browse your container and find your new procedure in the procedures folder. 9. A new SQL tab will be opened with the CALL statement inserted. Notice the technical schema name of your container is inserted here. 8. Switch over to the SAP HANA Runtime Tool(HRTT) via the following URL. 10. 93 .SAP HANA Extended Application Services. Right-click on the procedure and choose “Invoke Procedure”. Select the db module and choose Build->Build. Advanced model Development 7.

Click the “Run” button. Note the execution time.SAP HANA Extended Application Services. 94 .The two results are then shown in another tab. 13. 12. Advanced model Development 11.

The completed code should be similar to this. Explanation Screenshot 1. OUT EX_PO_CHANGE_CNT TABLE( CHANGE_CNT INTEGER. 2. Return to your procedure called “get_po_header_data”.EMPLOYEEID" NVARCHAR(10)). If you do not wish to type this code.SAP HANA Extended Application Services. "HISTORY.5.CHANGEDBY.2: Parallel Processing and Parameters In this exercise we will modify the code of procedure “get_po_header_data” so that it takes full advantage of the parallel processing within HANA by using table variables. 3.EMPLOYEEID" NVARCHAR(10)) ) LANGUAGE SQLSCRIPT SQL SECURITY INVOKER --DEFAULT SCHEMA <default_schema_name> READS SQL DATA AS BEGIN 95 . assign SELECT statements to the output parameters as shown here. Next. "HISTORY. Advanced model Development Exercise 2. 4. you can reference the solution web page at PROCEDURE "get_po_header_data" ( OUT EX_PO_CREATE_CNT TABLE( CREATE_CNT INTEGER. Define two tabular output parameters which will be used to explicitly pass the results of the SELECT statements to the caller.CREATEDBY.

EMPLOYEEID".EMPLOYEEID" FROM "PO.openSAP. 6. 7. Advanced model Development https://github.Header" WHERE PURCHASEORDERID IN ( SELECT PURCHASEORDERID FROM "PO.hana5. "HISTORY.EMPLOYEEID" FROM "PO.CHANGEDBY. END 5. Perform a build on the hdb module.Item" WHERE "PRODUCT. Return to the HRTT page and invoke the procedure again. Save the procedure.PRODUCTID" IS NOT NULL) GROUP BY "HISTORY.Header" WHERE PURCHASEORDERID IN ( SELECT PURCHASEORDERID FROM "PO. "HISTORY.CHANGEDBY.CREATEDBY.EMPLOYEEID".PRODUCTID" IS NOT NULL) GROUP BY "HISTORY.templates/ blob/master/ex2/ex2_18 ex_po_create_cnt = SELECT COUNT(*) AS CREATE_CNT. 8.com/SAP/com. ex_po_change_cnt = SELECT COUNT(*) AS CHANGE_CNT.SAP HANA Extended Application Services. 96 .Item" WHERE "PRODUCT. The CALL statement will be inserted into a new “SQL” tab.s ap.CREATEDBY.

97 . The reason is that these SQL statements are now executed in parallel. you may notice that it is a bit faster this time. 10.Check the execution time again. Advanced model Development 9.SAP HANA Extended Application Services. Click the “Run” button.

5.SAP HANA Extended Application Services. Rename EX_PO_CREATE_CNT to PO_CREATE_CNT. 3. 2.Define intermediate table variables “PO_CREATE_CNT” & “PO_CHANGE_CNT” and enrich the queries by an alias for employee id column (steps 2-3) . Also rename EX_PO_CHANGE_CNT to PO_CHANGE_CNT.Define a tabular output parameter that matches the result structure of the implicit query (step 1) . 4.Add a query that joins employee master data with the data from the two existing table variables and assign the result to the output parameter “EX_TOP_3_EMP_PO_COMBINED_CNT” (step 4) . Advanced model Development Exercise 2. 98 Screenshot . We will … .3: Intermediate Table Variables In this exercise we will modify the code of procedure “get_po_header_data” so that it leverages a tabular output parameter and intermediate table variables for later reuse. Delete the output parameters which you defined in the last section. Define a new output parameter as shown.Call the procedure (steps 5-9) Explanation 1. Switch back to the SAP Web IDE for SAP HANA and go return to your procdure.

Next.hana5. crcnt. CREATE_CNT INTEGER.Item" WHERE "PRODUCT.EMPLOYEEID" AS EID FROM "PO. If you do not wish to type this code.templates/ blob/master/ex2/ex2_19 PROCEDURE "get_po_header_data" ( OUT EX_TOP_3_EMP_PO_COMBINED_CNT TABLE( FULLNAME NVARCHAR(256). 7.EMPLOYEEID". add another SELECT statement after the 2 previous SELECT statements as shown. po_change_cnt = SELECT COUNT(*) AS CHANGE_CNT.s ap.CHANGEDBY.CREATEDBY.CREATE_CNT. 6.PRODUCTID" IS NOT NULL) GROUP BY "HISTORY. This statement uses the previously defined table variables.Header" WHERE PURCHASEORDERID IN ( SELECT PURCHASEORDERID FROM "PO. crcnt. chcnt. END 99 .CREATEDBY.PRODUCTID" IS NOT NULL) GROUP BY "HISTORY. Advanced model Development 5. The completed code should be very similar to this.EID ORDER BY COMBINED_CNT DESC LIMIT 3.EMPLOYEEID = chcnt.EMPLOYEEID" AS EID FROM "PO. CHANGE_CNT INTEGER.openSAP.EMPLOYEEID".Header" WHERE PURCHASEORDERID IN ( SELECT PURCHASEORDERID FROM "PO.SAP HANA Extended Application Services.CHANGE_CNT.LOGINNAME.CREATE_CNT + chcnt.Employees" as emp LEFT OUTER JOIN :PO_CREATE_CNT AS crcnt ON emp.EID LEFT OUTER JOIN :PO_CHANGE_CNT AS chcnt ON emp. EX_TOP_3_EMP_PO_COMBINED_CNT = SELECT emp. "HISTORY.Item" WHERE "PRODUCT.EMPLOYEEID = crcnt.CHANGE_CNT AS COMBINED_CNT FROM "MD. Modify the two SELECT statements and add “AS EID” after the EMPLOYEEID field.com/SAP/com.CHANGEDBY. "HISTORY. COMBINED_CNT INTEGER ) ) LANGUAGE SQLSCRIPT SQL SECURITY INVOKER --DEFAULT SCHEMA <default_schema_name> READS SQL DATA AS BEGIN po_create_cnt = SELECT COUNT(*) AS CREATE_CNT. you can reference the solution web page at https://github.

SAP HANA Extended Application Services. Advanced model Development 8. 9. Then return to the HRTT page and invoke the procedure. Save the procedure. 11.Click “Run”. Use what you have learned already and perform a build on your hdb module.The results are then shown. 100 . 10.

SAP HANA Extended Application Services.5. Enter the name of the file as “get_full_name” and click “Create”. Right click on the “functions” folder and choose “New”. then “Function”. We will … .Modify the procedure “get_po_header_data” by replacing the column “LOGINNAME” with our newly created scalar function using the alias “FULLNAME” (steps 7-10) .Create a new folder specifically for functions (steps 1) .Create a scalar function “get_full_name” that uses imperative SQLScript logic to concatenate the full name out of scalar input parameters (steps 2-6) . first and middle name of the employee.Call the procedure (steps 11-13) Explanation Screenshot 1. 2. 101 .4: Creating & Consume a Scalar Function In this exercise we are creating a scalar UDF for generating a full name from the last. Advanced model Development Exercise 2.

Return to your procedure called “get_po_header_data” and modify it. This is needed to match later on which the anticipated output structure. Start by renaming the “LOGINNAME” column of the output table to “FULLNAME”. Please note the default for parameter im_employeeid which makes assigning a value to the parameter optional.templates/ blob/master/ex2/ex2_20 FUNCTION "get_full_name" ( IN im_firstname NVARCHAR(40) . Enter the code into the editor as shown here. 5. you can reference the solution web page at https://github. IN im_lastname NVARCHAR(40). IF :im_employeeid <> '' then ex_fullname = :ex_fullname || '(' || :im_employeeid || ')'.hana5. IN im_middlename NVARCHAR(40).com/SAP/com. 4. IN im_employeeid NVARCHAR(10) DEFAULT '' ) RETURNS ex_fullname NVARCHAR(256) AS BEGIN if :im_middlename IS NULL THEN ex_fullname = :im_lastname || '. END. Also change the output length to 256. Advanced model Development 3. 102 . If you do not wish to type this code. END IF. Once again remove the double colon(::) from the function name.s ap. END IF. ' || :im_firstname. ' || :im_firstname || ' ' || :im_middlename.openSAP. ELSE ex_fullname = :im_lastname || '. Click “Save”. 6.SAP HANA Extended Application Services.

CHANGE_CNT. CHANGE_CNT INTEGER.s ap. Change the last SELECT statement.FIRST". 8. END 103 . "HISTORY.EID ORDER BY COMBINED_CNT DESC LIMIT 3. CREATE_CNT INTEGER.Header" WHERE PURCHASEORDERID IN ( SELECT PURCHASEORDERID FROM "PO.CREATE_CNT + chcnt. PO_CHANGE_CNT = SELECT COUNT(*) AS CHANGE_CNT. Remove the LOGINNAME column from the field list and replace it with a call to the scalar function that you created earlier. Advanced model Development 7.EMPLOYEEID".Header" WHERE PURCHASEORDERID IN ( SELECT PURCHASEORDERID FROM "PO.templates/ blob/master/ex2/ex2_21 PROCEDURE "get_po_header_data" ( OUT EX_TOP_3_EMP_PO_COMBINED_CNT TABLE( FULLNAME NVARCHAR(256).CREATE_CNT.EMPLOYEEID = chcnt. COMBINED_CNT INTEGER ) ) LANGUAGE SQLSCRIPT SQL SECURITY INVOKER --DEFAULT SCHEMA <default_schema_name> READS SQL DATA AS BEGIN PO_CREATE_CNT = SELECT COUNT(*) AS CREATE_CNT.Item" WHERE "PRODUCT. "NAME. Make sure to pass the NAME.MIDDLE and NAME.FIRST NAME.com/SAP/com. crcnt.PRODUCTID" IS NOT NULL) GROUP BY "HISTORY.CHANGEDBY. "NAME. If you do not wish to type this code.EMPLOYEEID" AS EID FROM "PO.MIDDLE".CHANGEDBY.CREATEDBY.LAST name columns to the scalar function call.EMPLOYEEID".EMPLOYEEID = crcnt.CREATEDBY. The completed code should look very similar to this.PRODUCTID" IS NOT NULL) GROUP BY "HISTORY.EID LEFT OUTER JOIN :PO_CHANGE_CNT AS chcnt ON emp. chcnt.EMPLOYEEID" AS EID FROM "PO.hana5.SAP HANA Extended Application Services. you can reference the solution web page at https://github. crcnt.CHANGE_CNT AS COMBINED_CNT FROM "MD.openSAP. "HISTORY.LAST") as FULLNAME.Item" WHERE "PRODUCT. EX_TOP_3_EMP_PO_COMBINED_CNT = SELECT "get_full_name"("NAME.Employees" as emp LEFT OUTER JOIN :PO_CREATE_CNT AS crcnt ON emp.

11. 12. 104 .Notice the FULLNAME column. Then return to the HRTT page and invoke the procedure. 10. Advanced model Development 9. it shows the results of the scalar UDF logic. Use what you have learned already and perform a build on your hdb module. Click “Save”. click “Run”. A new SQL tab will be opened.SAP HANA Extended Application Services.

Enter the name of the file as “get_po_counts”. filtering. and right click and choose “New”. Then click “Create”.Use the scalar input parameter “im_fdate” for filtering the column “CHANGEDAT” in the query assigned to table variables “po_change_cnt”.Create a table function “get_po_counts” with a scalar input parameter “im_fdate” and tabular return type that matches the output parameter structure of procedure “get_po_header_data” (steps 1-3) .e.Add a query on table variable “EMP_PO_COMBINED_CNT” as return statement (steps 9-11) . (step 5) . Advanced model Development Exercise 2.SAP HANA Extended Application Services. 2.5: Creating & Consume a Table Functions There are applications and scenarios where you need a table function instead of a procedure to leverage the advantage of direct selects on the output i. sorting and grouping.Query the TOP 3 employees by using a SELECT statement with LIMIT clause on the table function from the catalog view of the WEB IDE (steps 12-15) Explanation Screenshot 1.5. Return to the “functions” folder. The month of “CHANGEAT” should match the month of “im_fdate”. Do similar for the column “CREATEDAT” in the query assigned to table variables “po_create_cnt”.Remove the LIMIT from the final query and rename the table variable name to “EMP_PO_COMBINED_CNT” (steps 6-8) . In the following exercise we show you how you can easily transform a procedure to a table function. 105 . then “Function”.Copy the logic from the body of procedure “get_po_header_data” into the table function “get_po_counts” (step 4) . We will … .

FULLNAME NVARCHAR(256). Make sure to only copy the code between the BEGIN and END statements.hana5. 106 FUNCTION "get_po_counts"( im_fdate DATE ) RETURNS TABLE (EMPLOYEEID NVARCHAR(10). Enter the basic shell of the function as shown here. COMBINED_CNT INTEGER) LANGUAGE SQLSCRIPT SQL SECURITY INVOKER AS BEGIN END. Make sure to remove the double colon(::) at the beginning of the function name. Copy the logic from the procedure “get_po_header_data” into the body of the function. 5. Advanced model Development 3.com/SAP/com. Please note the scalar input parameter we will use later on for filtering. Add to the WHERE clauses in the first two SELECT statements for filtering by month. Month is captured from the input parameter im_fdate. If you do not wish to type this code.templates/ blob/master/ex2/ex2_22 4.SAP HANA Extended Application Services. .openSAP. you can reference the solution web page at https://github. CREATE_CNT INTEGER.s ap. CHANGE_CNT INTEGER.

templates/ blob/master/ex2/ex2_23 FUNCTION "get_po_counts"( im_fdate DATE ) RETURNS TABLE (EMPLOYEEID NVARCHAR(10). you can reference the solution web page at https://github.Item" WHERE "PRODUCT. 8.PRODUCTID" IS NOT NULL) AND MONTH("HISTORY.CREATEDBY. 9.hana5.s ap.Header" WHERE PURCHASEORDERID IN ( 107 . Finally.EMPLOYEEID" AS EID FROM "PO.CHANGEDBY. Also add the EMPLOYEEID column to the field list. The completed code should be very similar to this. FULLNAME NVARCHAR(256). CHANGE_CNT INTEGER.EMPLOYEEID". In the 3rd SELECT statement.EMPLOYEEID" AS EID FROM "PO. If you do not wish to type this code. change the name of the intermediate table variable to EMP_PO_COMBINED_CNT to match the variable name to the semantics of the query.openSAP. Advanced model Development 6. 7.CREATEDBY.Header" WHERE PURCHASEORDERID IN ( SELECT PURCHASEORDERID FROM "PO. CREATE_CNT INTEGER.SAP HANA Extended Application Services. "HISTORY. COMBINED_CNT INTEGER) LANGUAGE SQLSCRIPT SQL SECURITY INVOKER AS BEGIN PO_CREATE_CNT = SELECT COUNT(*) AS CREATE_CNT.com/SAP/com. Remove the LIMIT clause at the end. add a RETURN SELECT statement at the end to mark the to be returned result set of the function 10. "HISTORY. PO_CHANGE_CNT = SELECT COUNT(*) AS CHANGE_CNT.CREATEDAT") = MONTH(:im_fdate) GROUP BY "HISTORY.

PRODUCTID" IS NOT NULL) AND MONTH("HISTORY.EID LEFT OUTER JOIN :PO_CHANGE_CNT AS chcnt ON emp.CHANGEDBY. Then return to the HRTT page and invoke the function. chcnt.CREATE_CNT. Enter the date ’18. 14.EID ORDER BY COMBINED_CNT DESC . Advanced model Development SELECT PURCHASEORDERID FROM "PO.EMPLOYEEID". 108 SELECT * FROM "get_po_counts"('18. Use what you have learned already and perform a build on your core-db hdb module.Item" WHERE "PRODUCT.Employees" as emp LEFT OUTER JOIN :PO_CREATE_CNT AS crcnt ON emp. 11. "NAME.MIDDLE". crcnt. RETURN SELECT * FROM :EMP_PO_COMBINED_CNT. crcnt.2014’ as the input parameter. .CHANGEDAT") = MONTH(:im_fdate) GROUP BY "HISTORY.LAST") as FULLNAME.2014') LIMIT 3.FIRST". EMP_PO_COMBINED_CNT = SELECT EMPLOYEEID.12.EMPLOYEEID = crcnt. "get_full_name"("NAME. A new “SQL” tab will be opened with a SELECT statement.CHANGE_CNT AS COMBINED_CNT FROM "MD.CHANGE_CNT.12. Click “Save” 12.SAP HANA Extended Application Services. "NAME. END.EMPLOYEEID = chcnt. 13.CREATE_CNT + chcnt.

The results of your table function are then shown. 109 . Advanced model Development 15.SAP HANA Extended Application Services. Click the “Run” button. 16.

We will … .6: Debugging Stored Procedures In the following exercise we will show how to debug a procedure using the SQLScript debugger.Stepping through the procedure and resume to check the result (18-21) Explanation 1.Call the procedure “get_po_header_data” and stop during execution in the debugger (step 8) . From the menu. click the drop down box. This includes setting breakpoints.Evaluate expressions (steps 13-17) . 2. evaluating expressions and intermediate results. For the service name. Go to the HRTT page and open the procedure called get_po_header_data by double clicking on the procedure.5. 110 Screenshot .Step Over and investigate intermediate variables (steps 9-12) .SAP HANA Extended Application Services.Set a breakpoint in procedure “get_po_header_data” (steps 1-7) . Advanced model Development Exercise 2. choose SQL Debugger->Debug Settings 3.

SAP HANA Extended Application Services. 5. Click “Ok”. Click the “Connect” button. 6. Choose your container associated with your user id. then “Close” 111 . Advanced model Development 4. Click “Apply”.

You will notice that execution has stopped at your breakpoint and there is also the debug pane shown on the right. Use what you have learned and invoke and run the procedure. Click the “Step Over” button. 9.SAP HANA Extended Application Services. You might notice that this pane is currently not showing the intermediate table variables at this point. You can see all of the variables and parameters for this procedure. 112 . Set breakpoints at the lines shown here by simply clicking on the line number. 8. Advanced model Development 7.

12. a new local variable has been added. This is because it is not defined explicitly will be implicitly declared at runtime during first usage.A new window is then opened showing the data in the table.SAP HANA Extended Application Services. Review the data and close the window by clicking the “X” in the upper right hand corner. Advanced model Development 10. In the debugger pane. 113 . right click on it and choose “Display Content”.To see the data for this intermediate table variable.You will notice that execution has continued to the next statement. 11.

15.SAP HANA Extended Application Services. 16. You will notice the expression is then added to the “Expressions” section above. In the yellow box that appears below. Advanced model Development 13. enter a SELECT statement as shown here and hit “Enter”. 14. 114 . Click the “Toggle Expression Editor” button. Right click on the expression and choose “Display Content”.

Click the “Resume” button. Finally. 20. 115 . 19. display the contents of the output parameter the same way you did for the intermediate table variables. Once again click the “Step Over” button. Continue to step through the code and when execution stops at the END statement of the procedure.SAP HANA Extended Application Services. Advanced model Development 17. 18. Review the results and close the window by clicking the “X”. Notice the next intermediate table variables is also added. close the window by clicking the “X”. You can review the data in this table as well.

Exercise 2.Copy the logic from the body of procedure “get_po_header_data” into the body of the anonymous block statement (step 3) . 2. From the HRTT page. 116 Screenshot . Enter the these code in the SQL tab. Advanced model Development 21.Write an empty anonymous block skeleton in the SQL console of SAP Web IDE’s catalog view (steps 1-2) . Instead we will use so called anonymous blocks which is a fast and easy-to-use way for playing around and modifying SQLScript logic.Retrieve the desired result by executing the anonymous block (steps 6-8) Explanation 1. Return to the SQL tab and check the results. To have an anonymous block you need a do begin …end. We will … .5.SAP HANA Extended Application Services. Execution of the procedure is now completed. click the “SQL Console” button.Copy the logic from the signature of procedure “get_po_header_data” into the signature of the anonymous block statement (step 4) .7: Anonymous Blocks In this exercise we will show you how you can invoke SQLScript logic without the need to create a persistent logic container such as a procedure or function.

SAP HANA Extended Application Services. Make sure to only copy the code between the BEGIN and END statements.CHANGEDBY. PO_CHANGE_CNT = SELECT COUNT(*) AS CHANGE_CNT.Header" WHERE PURCHASEORDERID IN ( SELECT PURCHASEORDERID "PO. Ensure the parameter is assigned to a query parameter placeholder (?) as shown.CREATEDBY. Copy the signature from the procedure get_po_header_data into the signature part of the anonymous block. "HISTORY. If you do not wish to type this code.EMPLOYEEID" AS EID FROM "PO. CREATE_CNT INTEGER.EMPLOYEEID".s ap. "HISTORY.hana5. 5.CREATEDBY. Advanced model Development 3.PRODUCTID" IS NOT NULL) GROUP BY "HISTORY. CHANGE_CNT INTEGER.Item" WHERE "PRODUCT.PRODUCTID" IS NOT NULL) FROM 117 .Item" WHERE "PRODUCT. 4. COMBINED_CNT INTEGER) => ? ) BEGIN PO_CREATE_CNT = SELECT COUNT(*) AS CREATE_CNT.com/SAP/com. you can reference the solution web page at https://github.openSAP.EMPLOYEEID" AS EID FROM "PO.templates/ blob/master/ex2/ex2_24 DO ( OUT EX_TOP_3_EMP_PO_COMBINED_CNT TABLE( FULLNAME NVARCHAR(256). The completed code should look very similar to this. Copy the logic from the procedure “get_po_header_data” into the body.Header" WHERE PURCHASEORDERID IN ( SELECT PURCHASEORDERID FROM "PO.

EMPLOYEEID".Employees" as emp LEFT OUTER JOIN :PO_CREATE_CNT AS crcnt ON emp. END.CHANGE_CNT AS COMBINED_CNT FROM "MD.EID LEFT OUTER JOIN :PO_CHANGE_CNT AS chcnt ON emp.LAST") as FULLNAME.SAP HANA Extended Application Services. crcnt. 7. 6. 118 . You will notice that the SQLScript code is executed and results are shown.EMPLOYEEID = chcnt.CREATE_CNT. Click “Run”. "NAME. there is no procedure or function created here.CREATE_CNT + chcnt. Advanced model Development GROUP BY "HISTORY. Again. EX_TOP_3_EMP_PO_COMBINED_CNT = SELECT "get_full_name"("NAME. crcnt. chcnt.MIDDLE".CHANGE_CNT. "NAME. just the SQLScript being executed by the engine.FIRST".EID ORDER BY COMBINED_CNT DESC LIMIT 3.EMPLOYEEID = crcnt.CHANGEDBY.

Define an additional intermediate table variable “large_po_last_month” containing those purchase orders of last month exceeding the reference value.Retrieve the desired result by executing the anonymous block (steps 5-7) Explanation Screenshot 1. 2. Add the scalar input parameter called im_po_reference_value. (Step 2) We check if this table variable is empty using the IS_EMPTY function and only execute the remaining logic if it is not empty. (Step 3) . add a new SELECT statement which calculates the largest purchase orders.(For the sake of this example we ignore that we actually should compare the complete date.SAP HANA Extended Application Services. Immediately following the BEGIN statement.Add a scalar input parameter “im_po_reference_value” for the reference value.) We will … . Advanced model Development Exercise 2.5.8: Emptiness Checks In this exercise we will modify the code of the anonymous block to only calculate the logic in case there are purchase orders from last month exceeding a certain value. (Step 1) . 119 .

com/SAP/ com.SAP HANA Extended Application Services.PURCHASEORDERID FROM "PO. CREATE_CNT INTEGER. CHANGE_CNT INTEGER.sap. OUT EX_TOP_3_EMP_PO_COMBINED_CNT TABLE( FULLNAME NVARCHAR(256). 4.-1)) AND CURRENCY = 'EUR' GROUP BY PURCHASEORDERID HAVING SUM(GROSSAMOUNT) >= :im_po_reference_value.openSAP.Header" WHERE MONTH("HISTORY. Advanced model Development 3.templates/blob/master /ex2/ex2_25 DO ( IN im_po_reference_value BIGINT => 10000. you can reference the solution web page at https://github. Add an emptiness check IF statement which will skip logic in case no large purchase orders exist. COMBINED_CNT INTEGER) => ? ) BEGIN large_po_last_month = SELECT SUM(GROSSAMOUNT).hana 5. The completed code should look very similar to the following.CREATEDAT") = MONTH(ADD_MONTHS(CURRENT_DATE. IF NOT IS_EMPTY(:large_po_last_month) THEN 120 . If you do not wish to type this code.

Advanced model Development PO_CREATE_CNT = SELECT COUNT(*) AS CREATE_CNT.EMPLOYEEID" AS EID FROM "PO.PRODUCTID" IS NOT NULL) GROUP BY "HISTORY. Change the value of the scalar input parameter to 100000 and run the block again. "HISTORY. "NAME. crcnt.Header" WHERE PURCHASEORDERID IN ( SELECT PURCHASEORDERID FROM "PO. no result is shown.FIRST".CREATE_CNT.Item" WHERE "PRODUCT. 5.Header" WHERE PURCHASEORDERID IN ( SELECT PURCHASEORDERID FROM "PO.EMPLOYEEID" AS EID FROM "PO.MIDDLE". 6.EMPLOYEEID".LAST") as FULLNAME.CHANGEDBY. EX_TOP_3_EMP_PO_COMBINED_CNT = SELECT "get_full_name"("NAME.EMPLOYEEID = chcnt.Item" WHERE "PRODUCT. END IF.CREATE_CNT + chcnt.CREATEDBY. chcnt. "HISTORY.CREATEDBY.PRODUCTID" IS NOT NULL) GROUP BY "HISTORY. END.EID ORDER BY COMBINED_CNT DESC LIMIT 3.CHANGE_CNT AS COMBINED_CNT FROM "MD.EID LEFT OUTER JOIN :PO_CHANGE_CNT AS chcnt ON emp.EMPLOYEEID". crcnt. 121 .CHANGEDBY. Click Run. PO_CHANGE_CNT = SELECT COUNT(*) AS CHANGE_CNT. "NAME.CHANGE_CNT. The results are shown.SAP HANA Extended Application Services. 7.EMPLOYEEID = crcnt. You will notice that this time.Employees" as emp LEFT OUTER JOIN :PO_CREATE_CNT AS crcnt ON emp.

Advanced model Development 122 .SAP HANA Extended Application Services.

9. Click Create. then “Procedure”.9: Using Dynamic SQL.5. You will learn why it is better to use APPLY_FILTER then EXECUTE IMMEDIATE when using dynamic filtering.Save and call the procedure and check the result (steps 8-13) Explanation Screenshot 1. Advanced model Development Exercise 2.Treat this string as dynamic SQL statement and invoke it using EXEC function (step 6-7) . you will learn the differences between EXEC and EXECUTE IMMEDIATE . and APPLY_FILTER In this exercise. how to prevent SQL injection by using SQL injection prevention functions. 2.SAP HANA Extended Application Services.5. Enter the name of the procedure as dynamic_statements. Right click on the procedures folder and choose “New”.1: Using EXEC Statement We will … . SQL Injection prevention Functions. 123 .Create a procedure that uses scalar input parameters to construct a dynamic SQL statement string(steps 1-5) . Exercise 2.

Remove the double colon(::) from the beginning of the procedure name. The editor will then be shown. Because dynamic SQL is not supported in “Readonly” procedures. 4. 6. The completed code should look similar to this. 5. 124 .SAP HANA Extended Application Services. Advanced model Development 3. you must remove the “READS SQL DATA” keywords as shown here. Between the BEGIN and END statements. Add the default value ‘Laser printers’ to the im_category_filter_value parameter. both of type varchar with length of 5000. Add two input parameters named im_category_filter_value and im_field. insert the EXEC statements as shown.

hana5. If you do not wish to type this code.tem plates/blob/master/ex2/ex2 _26 PROCEDURE "dynamic_statements" ( IN im_field VARCHAR(5000). sqlstr = 'SELECT ' || :im_field || ' FROM "MD. EXEC(:sqlstr).sap.SAP HANA Extended Application Services. 10. you can reference the solution web page at https://github. 125 .com/SAP/co m. Switch to the SAP HANA Runtime Tools(HRTT) and browse your container and find your procedure.Products" WHERE CATEGORY = ''' || :im_category_filter_value || ''''. IN im_category_filter_value VARCHAR(5000) DEFAULT 'Laser printers' ) LANGUAGE SQLSCRIPT SQL SECURITY INVOKER AS BEGIN DECLARE sqlstr NCLOB. 9. The completed code should be very similar to this following.openSAP. Save the procedure by clicking Save. END 8. Advanced model Development 7. Select the core-db module and choose Build->Build.

Invoke the procedure by selecting the file and choosing Invoke Procedure. You will notice that you get no results from the call at all. 12. Advanced model Development 11. Click the Run button. 126 . 14. 13.SAP HANA Extended Application Services. there is a possibility of SQL injection. Add the input parameter values as shown. Click Format Code. Also by using the EXEC statement.

3.SAP HANA Extended Application Services.Use EXECUTE IMMEDIATE instead of EXEC (steps 1-3) . executing the string using EXECUTE IMMEDIATE returns a result set. 2.2: Using EXECUTE IMMEDIATE Statement In contrast to executing a string using EXEC.9. We will … . Replace the EXEC keyword with EXECUTE IMMEDIATE. 127 . Click Save. 4. Advanced model Development Exercise 2.Call the procedure (steps 4 -12) Explanation Screenshot 1.5. Switch back to the procedure editor in the SAP Web IDE for SAP HANA. Select the core-db module and choose Build->Build.

128 . But you still cannot work further on this result set. 6. Switch back to the SAP HANA Runtime Tools (HRTT). Click the Run button again.SAP HANA Extended Application Services. You will notice the implicit result set is now returned to the console. 7. Advanced model Development 5.

Click the Run button again. In the following you will see how to prevent SQL injection by using SQL injection prevention function. We will … .SAP HANA Extended Application Services.Modify the procedure to prevent these injection attempts from being effective by leveraging injection prevention functions (steps 10 – 15) .g. 3. Advanced model Development Exercise 2. 2. 4. user interface).Try to enforce abnormal behaviour of our previously created procedure by applying SQL injection during procedure invocation. 129 . there is a danger of an SQL injection attack.Call the procedure and see if we can prevent the injection attempts successfully (steps 16-24) Explanation Screenshot 1. Change the CALL statement as shown here. (steps 1 – 9) .3: Using SQL Injection Prevention Functions If your procedure needs execution of dynamic SQL statements where the parts of it are derived from untrusted input (e.5. Next we want to execute the procedure again with the aim of reading a completely different table with the following values. Change the CALL statement as shown.9. Next we can try to see whether we can access multiple columns or not. You will notice that you have just injected the procedure and the results of the Address table are shown.

Click Run 6. 7. Next. 8. You will notice that the results show multiple columns. Advanced model Development 5. you will notice that we are now getting all of the products regardless of the category. Click Run 9. The results are shown. we can try to get more values by bypassing the WHERE condition.SAP HANA Extended Application Services. 130 . Change the CALL statement as shown.

131 .templates/ blob/master/ex2/ex2_27 13. Next.com/SAP/com.com/SAP/com. If you do not wish to type this code. Switch back to the SAP Web IDE for SAP HANA and go to the dynamic_statements procedure.SAP HANA Extended Application Services.hana5.openSAP. you can reference the solution web page at https://github. Use the function SQL_INJECTION_SAFE to check the IM_FIELD contains safe simple SQL identifers. If you do not wish to type this code.s ap. Advanced model Development 10.templates/ blob/master/ex2/ex2_27 12. If you do not wish to type this code. 11.hana5. you can reference the solution web page at https://github.openSAP. use the function escape_single_quotes to guarrentee that the im_category_filter_value only contains delimited SQL identifiers.s ap. To prevent all these SQL injections above you have to use SQL injection prevention functions. In the case the check fails. then throw an error. you can reference the solution web page at PROCEDURE "dynamic_statements" ( IN im_field VARCHAR(5000). DECLARE mycond condition for sql_error_code 10001. The complete code should look very similar to the following. IN im_category_filter_value VARCHAR(5000) DEFAULT 'Laser printers' ) LANGUAGE SQLSCRIPT SQL SECURITY INVOKER AS BEGIN DECLARE sqlstr NCLOB.

hana5. END 14. Select the core-db module and choose Build->Build. 19. You will notice the call now fails with the user defined error. END IF. 17.openSAP. Click Save 15.templates/ blob/master/ex2/ex2_27 IF is_sql_injection_safe(im_field) <> 1 then SIGNAL mycond SET MESSAGE_TEXT = 'Invalid field: ' || :im_field. 132 .s ap. sqlstr = 'SELECT ' || :im_field || ' FROM "MD.com/SAP/com. Advanced model Development https://github. Switch back to the SAP HANA Runtime Tools and try again to inject the procedure by reading from a different table as shown.SAP HANA Extended Application Services. Now try again to read multiple values. Click Run 18. EXECUTE IMMEDIATE(:sqlstr). 16.Products" WHERE CATEGORY = ''' || escape_single_quotes(:im_category_filter_value) || ''''.

try again to get more values by bypassing the WHERE condition. Click Run 24. You will notice that you do not get any data. Finally.SAP HANA Extended Application Services. Advanced model Development 20. 133 . Click Run 21. You will notice the call fails again with the user defined error. 23. 22.

APPLY_FILTER is SQL injection save. We will … . Return to the procedure editor in the SAP Web IDE for SAP HANA and use what you have learned already to create a new procedure called get_product_by_filter.Call the procedure (steps 8 -17) . Make sure to remove the double colon(::) at the beginning of the procedure name.Create an empty procedure “get_product_by_filter” (step 1) . Furthermore the result of the APPLY_FILTER will be assigned to a table variable. (steps 4-5) .Products" as type definition (steps 18-19) .Define an output parameter named “ex_user_filtered_products” that with "MD. the procedure can be flagged read only which allows further optimization. Advanced model Development Exercise 2.4: Using APPLY FILTER Statement In contrast to EXEC and EXECUTE IMMEDIATE.Add scalar input parameter “im_product_filter_string” (step 2) .Remove the dynamic SQL statement and add a query that returns all products except of category “Laser printers” and assign the result to a new table variable “PRE_FILTERED_PRODUCTS” and add an APPLY_FILTER statement that applies the filter condition of the scalar string based input parameter “im_products_filter_string” on the table variable “PRE_FILTERED_PRODUCTS” (steps 21-23) - Call the procedure (steps 25-30) Explanation 1.5. This allows further processing of the result by referring to the table variable.Add a dynamic SQL statement using EXECUTE IMMEDIATE. The statement should return all products with a pre-defined filter on the product category excluding “Laser printers”. In addition a user defined filter based on the scalar input parameter “im_product_filter_string” should be applied as well on that table.Remove read only property from the procedure (step 3) .9. As APPLY_FILTER does not allow executing dynamic DML/DDL statements. 134 Screenshot .Mark the procedure as read-only (step 20) .SAP HANA Extended Application Services.

openSAP.templates/ blob/master/ex2/ex2_28 5.s ap.Products" where CATEGORY NOT IN (''Laser printers'')' || :im_product_filter_string . Advanced model Development 2. type varchar with a length of 5000. If you do not wish to type this code. 3. If you do not wish to type this code. you must remove the “READS SQL DATA” keywords as shown here 4. Because dynamic SQL is not supported in “Read-only” procedures. insert the EXEC statements as shown.SAP HANA Extended Application Services.s ap.openSAP. The completed code should look similar to this.com/SAP/com. Between the BEGIN and END statements. you can reference the solution web page at https://github. Click Save 135 .hana5. END 6.com/SAP/com.templates/ blob/master/ex2/ex2_28 PROCEDURE "get_product_by_filter" ( IN im_product_filter_string VARCHAR(5000) ) LANGUAGE SQLSCRIPT SQL SECURITY INVOKER --DEFAULT SCHEMA <default_schema_name> AS BEGIN EXECUTE IMMEDIATE 'SELECT count(*) FROM "MD. you can reference the solution web page at https://github.hana5. Add an input parameter named “im_product_filter_string”.

9. Results are shown. 136 .SAP HANA Extended Application Services. Switch over to the SAP HANA Runtime Tools and invoke the procedure called get_product_by_filter by rightclicking on the procedure and choosing Invoke Procedure. Enter the input parameter value as shown. Select the core-db module and choose Build->Build. Advanced model Development 7. 10. Click Run 11. 8.

This time insert the value for the input parameter as ‘OR 1 = 1’ as shown here. Results are shown. 18. Return to the get_product_by_filter procedure in the SAP Web IDE for SAP HANA. Advanced model Development 12. 16. Now change the CALL statement. 137 . Click Run 17. Results are shown. this time insert the value for the input parameter as ‘ ‘ as shown here. Click Run 14.SAP HANA Extended Application Services. 15. Now change the CALL statement again. 13.

hana5.s ap. Now that we are not using the dynamic SQL keywords.openSAP.Products table as the type. If you do not wish to type this code. you can reference the solution web page at https://github. Advanced model Development 19.openSAP. The APPLY_FILTER needs two input parameters: table variable which will used for filtering and a scalar variable which contains the string.s ap.hana5. we no longer need a read/write procedure.com/SAP/com.templates/ blob/master/ex2/ex2_29 20. you can reference the solution web page at https://github.com/SAP/com. If you do not wish to type this code. Remove the EXECUTE IMMEDIATE statement and instead insert the following SELECT statement and APPLY_FILTER statement using table variable assignments. Add an output parameter called “ex_user_filtered_products” and reference the MD.SAP HANA Extended Application Services. so add the READS SQL DATA before AS.templates/ blob/master/ex2/ex2_29 138 . 21.

SAP HANA Extended Application Services, Advanced model Development

22. The completed code should
be very similar to this.

If you do not wish to type this
code, you can reference the
solution web page at
https://github.com/SAP/com.s
ap.openSAP.hana5.templates/
blob/master/ex2/ex2_29

PROCEDURE "get_product_by_filter" (
IN im_product_filter_string varchar(5000),
OUT ex_user_filtered_products "MD.Products" )
LANGUAGE SQLSCRIPT
SQL SECURITY INVOKER
READS SQL DATA AS
BEGIN
pre_filtered_products = SELECT * FROM "MD.Products"
WHERE CATEGORY NOT IN
('Laser printers');
ex_user_filtered_products =
APPLY_FILTER(:pre_filtered_products,
:im_product_filter_string ) ;
END

23. Click Save.

24.Select the core-db module and
choose Build->Build.

25.Switch back to the SAP HANA
Runtime Tools(HRTT). Once
again invoke the procedure
again by right-clicking on the
procedure and choosing
Invoke Procedure.

139

SAP HANA Extended Application Services, Advanced model Development

26.Click Format Code.

27. Enter the filter string for the
input parameter as
'CATEGORY = ''Notebooks'''
and click Run.

28. Please note the result again
contains 10 records. The
results are displayed, but this
time they are passed through
a parameter which you are
able to access for further
processing.

29. Change the input parameter
value to ‘OR 1 = 1’ and click
Run again.

30. You will notice you now get
an error message when
passing ‘OR 1 = 1’ to the
procedure. This happens as
the provided string will no
longer be concatenated to the
predefined filter conditions.
Instead the provided string will
be treated as a stand-alone
filter condition, in this case
having an invalid syntax.

140

SAP HANA Extended Application Services, Advanced model Development

Exercise 2.5.10: Index Based Cell Access
Depending on the nature of the problem to be solved a solution using an imperative algorithm
might be worse to be considered. In the following exercise you will use the index based cell
access to write an imperative algorithm of calculate the cumulative sum of the number of
delivered products. In the Appendix you will find further variants that are using SQL, Arrays or
Cursors.
We will …
- Create another procedure called calculate_cumulative_sum_of_delivered_products(Step 1-9)
- Call this new procedure from the get_products_by_filter procedures(Steps 10 - 19)
- Call the procedure from the SAP HANA Runtime Tools(Steps 20-23)
Explanation

Screenshot

1. Use what you have learned
and create another procedure
called
calculate_cumulative_sum_of
_delivered_products in the
procedures folder. Make sure
to remove the double colon(::)
in the beginning of the
procedure name.
2. Insert input and output
parameters as shown.

If you do not wish to type this
code, you can reference the
solution web page at
https://github.com/SAP/com.s
ap.openSAP.hana5.templates/
blob/master/ex2/ex2_30
3. After the BEGIN statement,
enter the following DECLARE
statements.

If you do not wish to type this
code, you can reference the
solution web page at
https://github.com/SAP/com.s
ap.openSAP.hana5.templates/
blob/master/ex2/ex2_30

141

SAP HANA Extended Application Services, Advanced model Development

4. Next, enter the following code
to initialize the output table.

If you do not wish to type this
code, you can reference the
solution web page at
https://github.com/SAP/com.s
ap.openSAP.hana5.templates/
blob/master/ex2/ex2_30
5. Enter a FOR loop which will
iterate over the table variable
ex_products and perform the
calculation.

If you do not wish to type this
code, you can reference the
solution web page at
https://github.com/SAP/com.s
ap.openSAP.hana5.templates/
blob/master/ex2/ex2_30
6. Let’s look at the FOR loop you
just entered in more detail.
To calculate the size of the
table variable ex_products we
use here the cardinality
function of an array. Since this
function need an array as an
input we need to convert the
ex_product into an array by
using ARRAY_AGG. Continue
to the next step.
7. Here you can see how the
index based cell access will be
used. To write into a certain
cell or read from it you need to
specify the column name , e.g
num_delivered_products and
the index by using [<index>].
Continue to the next step.
8. The completed code should
look very similar to the
following.

142

PROCEDURE "calculate_cumulative_sum_of_delivered_products"
(
IN IM_PRODUCTS TABLE ( PRODUCTID NVARCHAR(10),
DELIVERYDATE DAYDATE,
NUM_DELIVERED_PRODUCTS BIGINT ),
OUT EX_PRODUCTS TABLE ( PRODUCTID NVARCHAR(10),
DELIVERYDATE DAYDATE,

SAP HANA Extended Application Services, Advanced model Development

If you do not wish to type this
code, you can reference the
solution web page at
https://github.com/SAP/com.s
ap.openSAP.hana5.templates/
blob/master/ex2/ex2_30

NUM_DELIVERED_PRODUCTS BIGINT,
CUMULATIVE_SUM BIGINT ) )
LANGUAGE SQLSCRIPT
SQL SECURITY INVOKER
READS SQL DATA AS
BEGIN
DECLARE tmp_productid NVARCHAR(10) = '';
DECLARE tmp_cumulated BIGINT
= 0;
DECLARE i
INTEGER
= 1;
ex_products = select products.*, NULL AS
CUMULATIVE_SUM FROM :im_products as products;
FOR i IN
1..CARDINALITY(ARRAY_AGG(:IM_PRODUCTS.PRODUCTID))DO
IF :tmp_productid <> :ex_products.PRODUCTID[:i]
THEN
tmp_productid = :ex_products.PRODUCTID[:i];
ex_products.CUMULATIVE_SUM[:i] =
:ex_products.NUM_DELIVERED_PRODUCTS[:i];
ELSE
ex_products.CUMULATIVE_SUM[:i] =
:ex_products.CUMULATIVE_SUM[:i-1]
+
:ex_products.NUM_DELIVERED_PRODUCTS[:i];
END IF;
END FOR;
END

9. Click Save.

10. Return to the
get_product_by_filter
procedure. Delete the output
parameter.

11. Define a new output
parameter called
EX_PRODUCTS. Instead of
referring to predefined table of
table type we are now using in
place table type definition.
If you do not wish to type this
code, you can reference the
solution web page at
https://github.com/SAP/com.s
ap.openSAP.hana5.templates/
blob/master/ex2/ex2_31

143

Item table as shown here. 13.templates/ blob/master/ex2/ex2_31 14.hana5.hana5. you can reference the solution web page at https://github. 144 . If you do not wish to type this code. Insert a call to the procedure called calculate_cumulative_sum_of _delivered_products and pass the aggregated_filtered_items variable as the input parameter and set products variable as the output parameter as shown.SAP HANA Extended Application Services.openSAP. Assign this statement to a table variable named aggregated_filtered_items. Next enter another SELECT which aggregates the results of the previous SELECT statement. you can reference the solution web page at https://github.com/SAP/com.com/SAP/com. Advanced model Development 12. Assign this statement to a table variable named filtered_items.s ap.openSAP.templates/ blob/master/ex2/ex2_31 15. Enter another SELECT statement which does an INNER JOIN between the results of the previous SELECT statement and the PO. If you do not wish to type this code. Rename EX_USER_FILTERED_PROD UCTS to USER_FILTERED_PRODUC TS.s ap.

s ap.hana5.SAP HANA Extended Application Services. If you do not wish to type this code.openSAP.templates/ blob/master/ex2/ex2_31 17. DELIVERYDATE ORDER BY PRODUCTID. Advanced model Development If you do not wish to type this code. filtered_items = select pi. :im_product_filter_string ) ."PRODUCT. add a SELECT statement at the end to assign the sorted results to the output parameter. OUT EX_PRODUCTS TABLE ( PRODUCTID NVARCHAR(10).s ap. CUMULATIVE_SUM BIGINT ) ) LANGUAGE SQLSCRIPT SQL SECURITY INVOKER READS SQL DATA AS BEGIN pre_filtered_products = SELECT * FROM "MD. DELIVERYDATE.PRODUCTID" as PRODUCTID.DELIVERYDATE from :user_filtered_products as p inner join "PO.templates/ blob/master/ex2/ex2_31 16. pi.s ap.productid = pi. you can reference the solution web page at https://github. DELIVERYDATE DAYDATE. CALL "calculate_cumulative_sum_of_delivered_products"( IM_PRODUCTS => :aggregated_filtered_items.com/SAP/com. The completed code should be very similar to the following.hana5.templates/ blob/master/ex2/ex2_31 PROCEDURE "get_product_by_filter" ( IN im_product_filter_string varchar(5000).com/SAP/com.Item" as pi on p. you can reference the solution web page at https://github.hana5. 145 . user_filtered_products = APPLY_FILTER(:pre_filtered_products.Products" WHERE CATEGORY NOT IN ('Laser printers'). EX_PRODUCTS => :products ) . you can reference the solution web page at https://github.openSAP. aggregated_filtered_items = SELECT PRODUCTID."PRODUCT. DELIVERYDATE. COUNT(PRODUCTID) AS NUM_DELIVERED_PRODUCTS FROM :filtered_items GROUP BY PRODUCTID.com/SAP/com. If you do not wish to type this code. NUM_DELIVERED_PRODUCTS BIGINT. Finally.PRODUCTID" .openSAP.

SAP HANA Extended Application Services. 19. 146 . Select the core-db module and choose Build->Build. DELIVERYDATE. Click Run. Enter the value for the input parameter as 'CATEGORY = ''Notebooks'' OR CATEGORY = ''PC''' 22. 21. Switch over to the SAP HANA Runtime Tools(HRTT) and invoke the get_product_by_filter procedure. END 18. Click Save. Advanced model Development ex_products = select * from :PRODUCTS order by PRODUCTID. 20.

Declare a custom exit handler for the custom condition within a nested BEGIN/END block. Add two additional input parameters for start and end date as shown. The exit handler should insert a new record into the log table and switch start date and end date in case the start date is larger than the end date (steps 20-25) .Create a logging error and messaging table using a .19) .1: Using Exception Handling In this example we will exchange the dates of the scalar input parameters to prevent the error in case the start date is larger than the end date.Call the procedure “get_product_by_filter” and check the content of the logging table (steps 24-29) Explanation Screenshot 1.11: Exception Handling. COMMIT & Autonomous Transactions Exercise 2.Introduce two scalar date input parameters to procdure “get_product_by_filter” which will be used to filter a range of valid delivery dates (steps 1-4) . Exercise 2.Remove IF statement from step 9 and declare a custom condition MYCOND as alias for error code 10001.11.hdbcds file (steps 13-16) . To do so we will rely on exception handling. 147 .Include a check for the two scalar input parameter and throw an error in case the check fails by signalling a user defined error code and error message (step 9) . We will … .SAP HANA Extended Application Services.Call the procedure “get_product_by_filter” (steps 10-12) . The results are shown. Advanced model Development 23. Return to the get_product_by_filter procedure in the procedure editor.Call the procedure “get_product_by_filter” (steps 5-8) .5.5.Remove read only property from procedure “get_product_by_filter” (step 17 .

templates/ blob/master/ex2/ex2_32 PROCEDURE "get_product_by_filter" ( IN im_product_filter_string varchar(5000). Advanced model Development 2. EX_PRODUCTS => :products ) . DELIVERYDATE DAYDATE."PRODUCT. END.hana5.openSAP. NUM_DELIVERED_PRODUCTS BIGINT. DELIVERYDATE ORDER BY PRODUCTID. The completed code should look very similar to this. aggregated_filtered_items = SELECT PRODUCTID. OUT EX_PRODUCTS TABLE ( PRODUCTID NVARCHAR(10). :im_product_filter_string ) . 3."PRODUCT. DELIVERYDATE. CUMULATIVE_SUM BIGINT ) ) LANGUAGE SQLSCRIPT SQL SECURITY INVOKER READS SQL DATA AS BEGIN pre_filtered_products = SELECT * FROM "MD. filtered_items = select pi. 148 . Add a WHERE clause to the third statement which filters the data by the start and end date input parameters.s ap.com/SAP/com. CALL "calculate_cumulative_sum_of_delivered_products"( IM_PRODUCTS => :aggregated_filtered_items. If you do not wish to type this code. user_filtered_products = APPLY_FILTER(:pre_filtered_products. you can reference the solution web page at https://github.Item" as pi on p. pi. ex_products = select * from :PRODUCTS order by PRODUCTID.Products" WHERE CATEGORY NOT IN ('Laser printers'). IN im_end_date date.DELIVERYDATE >= :im_start_date and pi.DELIVERYDATE <= :im_end_date.productid = pi. DELIVERYDATE. DELIVERYDATE.DELIVERYDATE from :user_filtered_products as p inner join "PO.SAP HANA Extended Application Services.PRODUCTID" where pi. COUNT(PRODUCTID) AS NUM_DELIVERED_PRODUCTS FROM :filtered_items GROUP BY PRODUCTID.PRODUCTID" as PRODUCTID. IN im_start_date date.

SAP HANA Extended Application Services. 9. Advanced model Development 4. 8. To do so please enter the following code after the BEGIN statement. Click “Save”. 7. 6. Enter the values for the input parameters as shown. Use what you have learned already and perform a build on your hdb module. Click “Save”. Then run the procedure. Return to the procedure called get_product_by_filter in the SAP Web IDE for SAP HANA. Then return to the HRTT page and invoke the procedure. 149 . We will include a check for the two scalar input parameters and throw an error in case the check fails. 5. Results are shown.

Instead we will handle the exception. Remove the IF statement that you inserted a little earlier. Since we will have a DML statement in the procedure we cannot flag it read only. You should see an error message showing user defined error 10001. 150 . Advanced model Development 10. you can see the message text as well. write the exception into a log table and continue with the procedure execution. If you scroll to the right. 12. 11. We do not want to stop the procedure execution by throwing a signal. Switch back to the procedure called “get_product_by_filter”. Please remove the “READS SQL DATA” statement. Then return to the HRTT page and change the input parameters as shown and run the CALL statement again. 14.SAP HANA Extended Application Services. 13. Use what you have learned already and perform a build on your hdb module.

CUMULATIVE_SUM BIGINT ) ) LANGUAGE SQLSCRIPT SQL SECURITY INVOKER AS BEGIN DECLARE temp_date DATE. The surrounding block. OUT EX_PRODUCTS TABLE ( PRODUCTID NVARCHAR(10).hana5. This exit handler will insert a new record in to the log table and will switch start date and end date accordingly. These variables return the name and schema of the procedure or function which is being executed. 17.openSAP. NUM_DELIVERED_PRODUCTS BIGINT. If you do not wish to type this code. execution will continue after the block. we use the two system variables ::CURRENT_OBJECT_NA ME and ::CURRENT_OBJECT_SC HEMA. marked by the BEGIN/END statements ensures that after the exception is caught. DELIVERYDATE DAYDATE.sap. you can reference the solution web page at https://github. Insert these DECLARE statements as shown. Advanced model Development 15. To know in which procedure or function the error was thrown. 16.tem plates/blob/master/ex2/ex2 _33 PROCEDURE "get_product_by_filter" ( IN im_product_filter_string varchar(5000). After the last DECLARE statement. Continue to the next step. Notice the last DECLARE statement is declaring a custom condition and assigning error code 10001 in the user defined number range. insert the following code.SAP HANA Extended Application Services.com/SAP/co m. IN im_start_date date. This code is declaring a custom exit handler for your custom condition. 151 . 18. The completed code should look very similar to the following. DECLARE MYCOND CONDITION FOR SQL_ERROR_CODE 10001. IN im_end_date date.

temp_date = :im_start_date. CALL "calculate_cumulative_sum_of_delivered_products"( IM_PRODUCTS => :aggregated_filtered_items. Advanced model Development BEGIN DECLARE EXIT HANDLER FOR MYCOND BEGIN DECLARE parameter NVARCHAR(256) = 'start_date = '|| :im_start_date || ' end_date = '|| :im_end_date. COUNT(PRODUCTID) AS NUM_DELIVERED_PRODUCTS FROM :filtered_items GROUP BY PRODUCTID."PRODUCT. 152 .PRODUCTID" as PRODUCTID. OBJECT_SCHEMA_NAME.Products" WHERE CATEGORY NOT IN ('Laser printers'). filtered_items = select pi. SQL_ERROR_MESSAGE) VALUES (current_timestamp. END IF. Click “Save”. SQL_ERROR_CODE.DELIVERYDATE from :user_filtered_products as p inner join "PO. :im_product_filter_string ) . PARAMETER. END.errors" (ERROR_TIMESTAMP.::CURRENT_OBJEC T_NAME. aggregated_filtered_items = SELECT PRODUCTID. :parameter . pre_filtered_products = SELECT * FROM "MD. END. END 19. ::SQL_ERROR_CODE. DELIVERYDATE ORDER BY PRODUCTID.productid = pi. OBJECT_NAME.DELIVERYDATE >= :im_start_date and pi. pi."PRODUCT. DELIVERYDATE.::CURRENT_OBJECT_SCHEMA. ::SQL_ERROR_MESSAGE). if :im_start_date > :im_end_date THEN SIGNAL MYCOND SET MESSAGE_TEXT = 'Start date must be smaller then end date'. im_end_date = :temp_date.PRODUCTID" where pi.Item" as pi on p. EX_PRODUCTS => :products ) . im_start_date = :im_end_date.DELIVERYDATE <= :im_end_date.SAP HANA Extended Application Services. user_filtered_products = APPLY_FILTER(:pre_filtered_products. DELIVERYDATE. INSERT INTO "log. DELIVERYDATE. ex_products = select * from :PRODUCTS order by PRODUCTID.

2: Using COMMIT Statement In this exercise will show the impact of a runtime error on DML statements and how to prevent it using COMMIT.11.SAP HANA Extended Application Services.errors. Advanced model Development 20. 24. Exercise 2.5. and click “Run”.errors and log. 22. You should see an error message in your table. Use what you have learned already and perform a build on your hdb module. This means that the exception was caught by the handler. enter a SELECT statements against your log.messages table as shown. Highlight the SELECT statement for log. Then return to the HRTT page and make sure the input parameters are as shown and run the CALL statement again. In the SQL tab. 21. 23. Notice the results of the procedure are returned. and execution was allowed to continue since you saw the results of the procedure call. We will… 153 .

5. 2. Select the SELECT statement for log. and click ‘Run’. Select the entire CALL statement. Here we are adding a filter on a column which we know does not exists in hopes of causing an error and transaction rollback. 154 Screenshot . 3.errors again and click “Run” to check the table contents. Return to the SQL tab and change the filter value for the first input parameter.SAP HANA Extended Application Services. Advanced model Development - - Call procedure “get_product_by_filter” with a filter string that contains a non-existing column as well as a start date that is larger than the end date and check the logging table for the expected error message (steps 1-5) Add another INSERT statement to the procedure that writes an entry in the message table (step 6-7) Add a COMMIT statement after the INSERT statement In the exception handler to ensure that the error message gets persisted into the log table in any case (step 8) Call procedure “get_product_by_filter” with similar filter conditions as above and check the content of the logging and messaging table (steps 9-14) Explanation 1. Of course we get the error “invalid column name”. You will notice that a new row was not inserted into the log table due to transaction rollback. 4.

Then return to the HRTT page and make sure the input parameters are as shown and run the CALL statement again.You will still get the error for invalid column.errors and click “Run” to execute it.SAP HANA Extended Application Services. Insert this INSERT statement with BEGIN and END blocks after the DECLARE statements as shown. Select the SELECT statement for log. 11. Let’s insert a DML statement for the sake of showing the behavior of COMMIT. Click “Save”. 8. Return to the procedure called “get_product_by_filter”. To avoid the deletion of the log entry in case of transaction rollback.Use what you have learned already and perform a build on your hdb module. 155 . 7. we will use an explicit COMMIT. Advanced model Development 6. 9. After the INSERT statement with in the EXIT HANDLER. add a COMMIT statement. 10.

5. Advanced model Development 12. but also “Chuck Norris” found its way into our log.messages table. You will now notice that the new row has been inserted into the log table even though there was an error and a ROLLBACK was executed. The end of the autonomous transaction block has an implicit commit. Changes made and committed by an autonomous transaction can be stored in persistency regardless of commit/rollback of the main transaction.SAP HANA Extended Application Services. A better solution for this are the autonomous transaction Exercise 2. 13.Remove the COMMIT statement in procedure “get_product_by_filter” and instead wrap the INSERT statement with an AUTONOMOUS TRANSACTION block (steps 1-2) .errors table. 14.11.3: Using Autonomous Transactions The autonomous transaction is independent from the main procedure transaction. We will … . Highlight the SELECT statement for log.messages and click “Run”. The complete transaction will be committed.Call procedure “get_product_by_filter” with similar filter conditions as above and check the content of the logging and messaging table (steps 3-8) Explanation 156 Screenshot . As you can see not only was the new record inserted into the log. meaning any modification happened in this transaction will be persisted.

Advanced model Development 1. Then return to the HRTT page and make sure the input parameters are as shown and run the CALL statement again.errors table.SAP HANA Extended Application Services.errors table and click “Run” to execute it. 2. Use what you have learned already and perform a build on your hdb module. 6. Click “Save”. Return to the procedure called “get_product_by_filter”. 4. Remove the COMMIT statement. Select the SELECT statement for the log. You will still get the error for invalid column. 3. 5. and instead wrap the INSERT statement with an AUTONOMOUS TRANSACTION block as shown. 157 . You will now notice that a new row was entered into the log.

158 . Advanced model Development 7.messages table and click “Run” to execute it. “Chuck Norris’s” record was removed by the rollback (“Is that even possible…?”) by using AUTONOMOUS TRANSACTION blocks.SAP HANA Extended Application Services. Another “Chuck” record was not inserted. the code within is isolated from the rest of the mainline code and is treated as a separate transaction. 8. Select the SELECT statement for the log.

js to provide XSJS and XSODATA backward compatibility.js. Exercise Description  Node. classic even within this new environment. . SAP has added modules to node.SAP HANA Extended Application Services. Therefore you can use the same programming model and much of the same APIs from XS. Although XS Advanced runs on node. Advanced model Development EXERCISE 3 –XSJS AND XSODATA SERVICES Objective For this exercise we will now build the XSJS and XSODATA services used to expose our data model to the user interface.js XSJS Bootstap  XSJS Services  XSODATA Services 159 .

we will start by creating a new module. New->Node. Name the module core-js and press Next. 160 Screenshot .js Module 2.1: XSJS and XSODATA Explanation 1.SAP HANA Extended Application Services. Advanced model Development EXERCISE 3 – SOLUTION Exercise 3. Like the previous exercises.

The complete section for the web module should now look like this: modules: . Now we need to add the dependency from the web module to this new nodejs module and to add a destination route to it as well. We also need to make sure the module is exposed for use in the destination route. Then press Finish.name: hdi-container . It will need a dependency to both the uaa and hdi resource.name: core-js-service properties: url: "${default-url}" requires: .name: web type: html5 path: web requires: .yaml file has been extended to add the js module. Be sure to check the box Enable XSJS support.name: core-js-service group: destinations properties: name: core-backend url: ~{url} forwardAuthToken: true Note: if you don’t want to type this code. The complete section for the js module should now look like this: .SAP HANA Extended Application Services. we recommend that you cut and paste it from this web address https://github.s ap. Advanced model Development 3. We also need to extend the new js module that was just created.templates/ blob/master/ex3/ex3_1 5.name: core-js type: nodejs path: core-js provides: .name: openSAPHANA5_<group number>-uaa .openSAP.name: openSAPHANA5_<group number>-uaa .hana5. 4. Once again the mta.com/SAP/com.name: core-db 161 .

the destination routing builds a dependency and navigation ability between the two services without ever having to hard code the URLs or ports. { "source": "(. "authenticationType": "xsuaa" }.xsodata)".json of the App Router (web module). "destination": "core-backend".hana5.openSAP.templates/ blob/master/ex3/ex3_3 162 { "welcomeFile": "index.templates/ blob/master/ex3/ex3_2 Later at deploy. They are assigned at deploy time and all references are automatically updated.openSAP. This is where we are configuring that any file request with the extension .xsjs)".xsjs or .hana5. "routes": [{ "source": "(. "authenticationType": "xsuaa" }] } . Now we can add rules for redirecting certain requests to the web module into other modules in this project.com/SAP/com. "csrfProtection": false. Advanced model Development Note: if you don’t want to type this code.s ap. If you remember back to exercise 1 – we maintained the xs-app. Note: if you don’t want to type this code.*)(. "authenticationMethod": "route".*)(.SAP HANA Extended Application Services.yaml. 6.com/SAP/com. we recommend that you cut and paste it from this web address https://github.html". we recommend that you cut and paste it from this web address https://github.xsodata should be rerouted internally to the nodejs destination that we just defined in the mta. "destination": "core-backend".s ap.

js is the node.js should look like this now: Note: if you don’t want to type this code. We want authentication on our service.hana5. } // start server xsjs(options). xsenv. err.extend(options.PORT || 3000.env.com/SAP/com. This server.SAP HANA Extended Application Services. console. var xsjs = require("sap-xsjs"). } // configure UAA try { options = xsjs. var xsenv = require("sap-xsenv").templates/ blob/master/ex3/ex3_4 /*eslint no-console: 0. } catch (err) { console. err. but one that we’ve created via the module creation wizard.js bootstap for XSJS compatibility mode.getServices({ hana: {tag: "hana"} })). Advanced model Development 7. We want to make a few changes to what the wizard generated.getServices({ uaa: {tag: "xsuaa"} })). so comment out the anonymous: true line. 163 .log("[WARN]". xsenv. Like the other applications. } catch (err) { console. this one also starts with a package.xsjs" }). It uses the SAP provided xsjs module and starts it with a few basic parameters. port).listen(port). Return to the core-js folder that we created in this exercise. // remove to authenticate calls redirectUrl : "/index. 8. var port = process. we recommend that you cut and paste it from this web address https://github.extend({ // anonymous : true.log("Server listening on port %d".extend(options.s ap. Different this time is the fact that the startup script is not an SAP provided central node application.message). However remember all the HANA database connectivity options come from the HDI container which we bound to this service via the mta.openSAP. // configure HANA try { options = xsjs. no-unused-vars: 0*/ "use strict".message). var options = xsjs.json file.log("[WARN]". The complete implementation of server.yaml file.

openSAP. "PurchaseOrder.status = $.In the lib folder. create a subfolder called xsodata. Here is the source code for this file. filename=Excel.length.set("Content-Disposition".contentType = "application/vnd.xsodata.xsjs.ms-excel.response. Here is the source code for this file.templates/ blob/master/ex3/ex3_6 This logic reads data from our item table. In the lib folder. var body = "".getConnection(). } } $. $. Create a file named hdb. for(var i = 0. " + " PRODUCT as \"ProductID\". 164 .Header" as "POHeader" navigates ("Items" as "POItem").Item" as "POItem". var conn = $.s ap. Note: if you don’t want to type this code. we recommend that you cut and paste it from this web address https://github.net.openSAP. " + " GROSSAMOUNT as \"Amount\" " + " } ".SAP HANA Extended Application Services. " + " PURCHASEORDERITEM as \"ItemPos\".response. dot-notation: 0*/ "use strict". var rs = conn.hana5.Item { " + " PURCHASEORDERID as \"PurchaseOrderItemId\". association "Items" principal "POHeader"("PURCHASEORDERID") multiplicity "1" dependent "POItem"("PURCHASEORDERID") multiplicity "*". Advanced model Development 9. create a subfolder called xsjs.com/SAP/com. no-unused-vars: 0.templates/ blob/master/ex3/ex3_5 service { "PurchaseOrder.xls").hana5. "attachment. Note: if you don’t want to type this code. /*eslint no-console: 0. i < rs.com/SAP/com.http.response.executeQuery(query). var query = "SELECT FROM PurchaseOrder.OK. $. } Here we expose both the Header and Item tables from our HDI container as separate entities and build a navigation association between the two.s ap.hdb. charset=utf-16le". Create a file named purchaseOrder. we recommend that you cut and paste it from this web address https://github. i++){ if(rs[i]["Amount"] >= 500){ body += rs[i]["PurchaseOrderItemId"] + "\t" + rs[i]["ItemPos"] + "\t" + rs[i]["ProductID"] + "\t" + rs[i]["Amount"] + "\n".setBody(body). 10.headers. formats it as text table delimited and then sends it out in a way that the browser will treat it as an Excel download. $.response.

response.setBody(body). body = JSON.hana5. } 12. /*eslint no-console: 0.OK. dot-notation: 0*/ "use strict". This is an empty file which we can use to request a CSRF token for update/insert/delete operations.net. //Pass output to response $.openSAP. This example shows you how to call a stored procedure from XSJS. $.com/SAP/com.response.setBody(JSON.setBody("Invalid Request Method").response.session. $. Note: if you don’t want to type this code. we recommend that you cut and paste it from this web address https://github. "Language": $.stringify({ "session" : [{"UserName": $. nouse-before-define: 0*/ "use strict". we recommend that you cut and paste it from this web address https://github.status = $.http.net.xsjs.INTERNAL_SERVER_ERROR.hana5.openSAP.Create a second file named exercisesMaster.s ap. no-unused-vars: 0. $.status = $.stringify(results)).contentType = "application/json".parameters. Note: if you don’t want to type this code.contentType = "application/json".response.net. 13.status = $. break.xsjs.getUsername().response. switch (aCmd) { case "getSessionInfo": fillSessionInfo(). } var aCmd = $.request.SAP HANA Extended Application Services. no-unused-vars: 0.xsjs. function fillSessionInfo(){ var body = "".Create a forth file named procedures. Here is the source code for this file.OK. } /** @function Flattended JSON structure */ function hdbFlattenedTest(){ 165 .response. $.response.com/SAP/com.templates/ blob/master/ex3/ex3_7 It sends the current user and language back to the client for filling in the header of the UI. /** @function JSON as returned by hdb */ function hdbDirectTest(){ var results = _selection().language}] }).templates/ blob/master/ex3/ex3_8 /*eslint no-console: 0.http. default: $. dot-notation: 0.s ap.session. Advanced model Development 11. $.get("cmd").http.Create a third file named csrf.response. $.

Create a 5th file called os.response. var getPOHeaderData = connection.JSON Object */ function outputJSON(jsonOut){ var out = [].EX_TOP_3_EMP_PO_COM BINED_CNT).push(jsonOut[i]).OK. . } var aCmd = $.endianness = os. } $.response.setBody(JSON.length. break.request.parameters.i++){ out. Advanced model Development outputJSON(_selection(). output.xsjs.loadProcedure( "get_po_header_data"). for(var i=0. $. we recommend that you cut and paste it from this web address 166 /*eslint no-console: 0.tmpdir = os. switch (aCmd) { case "direct": hdbDirectTest(). } /** @function load/call the procedure */ function _selection(){ var connection = $.SAP HANA Extended Application Services. output.response. output. Note: if you don’t want to type this code.getConnection(). case "flattened": hdbFlattenedTest(). default: hdbDirectTest().endianness().get("cmd"). var results = getPOHeaderData().stringify(out)). } /** @function Puts a JSON object into the Response Object @param {object} jsonOut . break. i<jsonOut.contentType = "application/json".js from XSJS.status = $. var output = {}. break.hostname().hostname = os. } 14.hdb. $.tmpdir(). no-unused-vars: 0*/ "use strict".require("os"). var os = $. This example shows you how you can call to Node.net.http. return results.

output.So now run the web module.response.platform = os. We can now run the core-js module.hana5.SAP HANA Extended Application Services.OK.setBody(JSON.contentType = "application/json". $. 15.openSAP.freemem = os. output.loadavg = os.arch(). output.response. output.freemem(). output.totalmem(). output.cpus().totalmem = os.type = os. output. output.release = os.type(). 167 .platform().status = $.response.templates/ blob/master/ex3/ex3_9 output. 16. You should see that the build and deploy was successful. The initial build can take a few minutes. output.loadavg().networkInfraces = os.uptime = os.net.networkInterfaces(). Save any unsaved/open files. It will need to rebuild and redeploy due to the added dependency to the js module. $.cpus = os. $.release().arch = os.s ap.com/SAP/com. 17.stringify(output)).uptime().http. Advanced model Development https://github.

Feel free to test the other example xsjs files we created in this exercise as well.In the running tab. We can add the url to our xsjs service /index. you should see the index.xsjs reads data from our new Purchase Order table we created in HANA in the previous exercise and exports it as an Excel text file./xsjs/hdb. The HTML5 module functions as a proxy and performs the routing to the other service internally. 19.xsjs in the browser. You will see that our xsjs service is accessible via the HTML5 module runtime.html from earlier. 168 . Advanced model Development 18.SAP HANA Extended Application Services.

xsod ata?$format=json gives you access to a full OData service for the Purchase Order header and item tables we created in the previous exercise./xsodata/purchaseOrder.SAP HANA Extended Application Services. 169 . Advanced model Development 20.

.xsjs file to set a breakpoint on line 7. Return to the SAP Web IDE for SAP HANA and click in the left side of the editor of the os.2: Debugging XSJS or Node... Advanced model Development Exercise 3.SAP HANA Extended Application Services. 170 Screenshot .js Explanation 1. Right mouse click on the core-js folder and choose Run -> Run Configurations. We want to restart the service in debug mode via a special runtime configuration. 2.

After the core-js service is finished restarting switch the browser window to the where the web module is running and change the url path to /xsjs/os. Name the configuration Debug OS. 5. Advanced model Development 3. Click Save and Run.js Applciation Run Configuration 4. The debugger should attach and open in the editor. 171 .xsjs and click the Debug Enabled checkbox. Create a new Node.xsjs 6.SAP HANA Extended Application Services.

Step over some statemetns. Try adding the output vaiable to the Console. You can now spend a moment exploring the debugger. Advanced model Development 7. 172 .js.SAP HANA Extended Application Services. you can restart the service in normal operation by choosing Run->Run server. When you are finished.

sap. 173 .SAP HANA Extended Application Services. There is no strict right or wrong solution to many of these exercise parts.ha na. 2) You should also import the supporting xsjs libraries from here: https://github.sap.hana5. this exercise will instead allow you to explore various JavaScript language features.3: Exploring JavaScript Language Features Explanation Screenshot 1) This exercise will be a bit different from all others. However you can import sample solutions from: https://github.democontent.com/SAP/com .epm.servic es.openSAP.com/SAP/com .zip Feel free to create similar xsjs files in order to be able explore these language features. However the main point of this exercise is to focus on general JavaScript language constructs and not anything XSJS or HANA specific.hana.templ ates/raw/master/ex3/JavaS criptBasics. Advanced model Development Exercise 3.epm . Instead of following along step-by-step or working toward a very specific final product.templ ates/raw/master/ex3/sap.hana5.openSAP.democontent.services to forward slashes to create the necessary folder structure.zip Upon import change the dots in sap.

xsjs 4) Create a Data object with the current date. Day. Convert the string to all upper and all lower case. Minutes. Advanced model Development 3) Create a string with some sample text in it. JSON. Sample implementation: strings. Perform a find and replace operation on the string. Month.SAP HANA Extended Application Services. Convert the data to various other formats (UTC. Access the last character in the string. Sample implementation: dates. adding 30 days to the current date.xsjs 174 . Perform math on a date. ISO. Hours. Access the sub-parts of the date: Year. Local Time. Access the first character of the string. and Seconds. Find the last occurrence of a character in the string. Output the length of the string. Local Data. Find the position of a particular text part of the string.

Loop over the first array and output each element. Sample implementation: array. Access the first element by index. Remove the last and then first element. Orange. Get the number of elements in the first array.SAP HANA Extended Application Services. Slice out the 3rd and 4th element. Reverse Sort and then Sort Ascending.xsjs 175 . and Purple. Combine the two arrays. Add two new colors (Malachite and Fallow) at the 3rd position. and Blue and one with Black. Get the index of Blue in the first array. White. Add Brown to the start of the Array. Output the first array as a string. Green. Advanced model Development 5) Create two arrays: one with the colors Red.

Advanced model Development 6) The reusable library session.services allows you to convert record set objects to JSON.xsjslib in sap.SAP HANA Extended Application Services.epm .democontent. Loop over the elements in the JSON object and create a new DISCOUNTAMOUNT attribute by discounting the GROSSAMOUNT by 10%.xsjs 176 . Convert the JSON object to a string and output it to the frontend.Header and convert the results to JSON.hana. Select 10 records from PO. Sample implementation: json.

Advanced model Development 7) Create an object literal called colors. and a calculated discount amount (10% off gross amount). Prove that objects are assign by reference and not assign by value. Give the object a function named favoriteColor. Create two instances of this object – one for PO 300000000 and one for 300000001 Sample implementation: objects. Access the colors in the object including the Favorite color.SAP HANA Extended Application Services.xsjs 177 . On Monday it should return blue. gross amount. Create a purchase order object for PO.Header which returns PO Id. all other days it returns red. and blue with the value #0000FF. green with the value #00FF00. Give it three properties – red with the value #FF0000.

services.4: Creating an XSJS Service with outbound HTTP Connectivity Explanation Screenshot 1) XSJS services can also make outbound HTTP calls.yaml.SAP HANA Extended Application Services.epm.images -p "{\"host\":\"www.yaml 178 xs cups sap. 2) The base configuration of an xshttpdestination is now an XSA user provided service similiar to those we created earlier for DB access to existing schemas. Advanced model Development Exericse 3.loc. In this step we will extend the previous service to make a request to the Library of Congress Image database and return the results to HANA.\"port\":\"80\".democontent.\"tags\":[\"xshttpdest\"] }" .hana. 4) Add add this resources as a dependency of the core-js module in the mta. 3) Add this service as a resource in the mta.gov\".

7) Test the application in your browser using the “Run” button. Once again you will need to adjust the service to add the cmd and the search string. It already contains an xsjs named outboundTest. There is a function to the service to call the outbound HTTP connection.x sjs?cmd=Images&search= HANA 179 .xsjs. Take in to additional URL parameters for the remote search term and the image index in the search results. For example if your group number was 00 and you wanted to search for images of HANA then the URL would be: /sap/hana/democontent/ep m/services/outboundTest.SAP HANA Extended Application Services.3 you should have imported the /lib/sap/hana/democontent/ epm/services folder. Re-run the core-js service to pickup the new user provided service resource. 6) There is also the entry point logic. Advanced model Development 5) In exercise 3.

Advanced model Development 8) You can page through the search results by adding the index URL parameter. To search for the 10th image in the HANA results set use this URL: /sap/hana/democontent/ep m/services/outboundTest.x sjs?cmd=Images&search= HANA&index=10 180 .SAP HANA Extended Application Services.

This concept still continues in XSJS in XSA. 4) Add add this resources as a dependency of the core-js module in the mta. Advanced model Development Exericse 3. xs cups CROSS_SCHEMA_SFLIGHT_<group number> -p "{\"host\":\"<hostname>\".db. but now we utilize a User Provided Service as the basis of the configuration.jdbc. The name should be CROSS_SCHEMA_SFLIG HT_<group number>.Driver\". 2) Let’s reuse the SFLIGHT user created service which you should have already created back in exercise 2.yaml as well. 181 .\"user\":\"<user>\".\"driver\":\"c om.5: User Provided Service as SQLCC Explanation Screenshot 1) XSJS in XSC had a concept called SQLCC where you could force database queries to run as a different user than the logged on user.sap. \"schema\" : \"SFLIGHT\" }" 3) Declare a new resource in our mta.5.\"port\":\"3<Instance Number><15|13>\".SAP HANA Extended Application Services.yaml for the existing service but name this new resource CROSS_SCHEMA_SFLIG HT.\"password\":\"<Password>\".\"tags\":[\"hana\"] .

"pool": true }).getConnection({"sqlcc": "xsjs.executeQuery(query).setBody(greeting).response. var greeting = "XS Layer Session User: " + $.sqlcc_config". var query = "SELECT CURRENT_USER FROM \"DUMMY\"".session. we recommend that you cut and paste it from this web address https://github. query = "SELECT SESSION_CONTEXT('APPLICATIONUSER') \"APPLICATION_USER\" FROM \"DUMMY\"".SAP HANA Extended Application Services. 6) In the lib/xsjs folder. $.xsjs.response.sap.tem plates/blob/master/ex3/ex3 _10 var connection = $.contentType = "text/html.executeQuery(query). $.CURRENT_USER. var currentUser = rs[0]. Re-run the core-js service to pickup your changes. charset=utf-8".hdb.APPLICATION_USER.hana5. create a file named whoAmI_SQLCC. 7) Save the open files. Note: if you don’t want to type this code. var rs = connection. Advanced model Development 5) We now need to return to the server.openSAP. rs = connection.getUsername() + "</br>Database Current User: " + currentUser + "</br> Database Application User: " + applicationUser + "</br>Welcome to HANA ".com/SAP/co m. 182 . Use the following code to connect to the database using the User Provided Service configuration and output the current user. var applicationUser = rs[0].js in the core-js module and extend the xsjs bootstrap.

you should see whichever user was configured in the User Provided Service.SAP HANA Extended Application Services. Advanced model Development 8) The path to your service should be /xsjs/whoAmI_SQLCC. 183 .xsjs Instead of the HDI container technical user as theser Database Current User.

SAP HANA Extended Application Services, Advanced model Development

Exercise 3.6: Creating a Simple OData Service
Explanation
1) Right mouse click on the
core-js/lib/xsodata folder
and choose New->File.

2) Enter the name as
businessPartners.xsodata
and click “OK”.

3) 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
(MD.BusinessPartner) and
the name of the OData
entity (BusinessPartners).
Therefore the content of the
XSODATA file would be.

184

Screenshot

SAP HANA Extended Application Services, Advanced model Development

4) Save the file. Run the
Node.js module. Then
return to the running html5
module. Change the url
path to
/xsodata/businessPartners.
xsodata/?$format=json to
test this new service.
The resulting document
describes the service
entities. We only had the
one entity named
BusinessPartners.

5) You can now adjust the
URL slightly and add the
/$metadata parameter to
the end of it.
For Example:
/xsodata/businessPartners.
xsodata/$metadata

You can see the field details
for all the attributes of the
OData service.

185

SAP HANA Extended Application Services, Advanced model Development

6) In order to view the data of
the entity, you would
append BusinessPartners
to the end of the URL:
For Example:
/xsodata/businessPartners.
xsodata/BusinessPartners?
$format=json
You are now able to see the
data from the
businessPartner table.

7) 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:
/xsodata/businessPartners.
xsodata/BusinessPartners?
$top=3&$skip=5&$format=j
son

186

SAP HANA Extended Application Services, Advanced model Development

Exercise 3.7: 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 the editor,
you should now create
a new OData service
named
purchaseOrders.xsoda
ta and extend it to
include the PO.Header
and PO.Item tables.
Next create a
navigation 1:many
association.
The new content of the
definition file should
look like this:
Note: if you don’t want
to type this code, we
recommend that you
cut and paste it from
this web address
https://github.com/SAP
/com.sap.openSAP.ha
na5.templates/blob/ma
ster/ex3/ex3_11

187

SAP HANA Extended Application Services, Advanced model Development

3) Save, run and test
using the same steps
as in the previous
section of this
exercise.
Notice that the base
service definition now
has two entities

4) The Header data now
has a hyperlink
relationship to the item
entity

188

SAP HANA Extended Application Services, Advanced model Development

5) 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.

189

SAP HANA Extended Application Services, Advanced model Development

Exercise 3.8: Creating an OData Service with Create Operation and XSJS Exit
Explanation

Screenshot

1) For the next OData
service we want to use
the User entity, but
remember back to
exercise 2 we isolated
this database object
into its own HDI
container. Therefore
we should also isolate
the node.js service that
exposes this entity.
Create another node.js
module named user-js.

2) To save time, we’ve
already create a
skelleton
implementation of the
user-js module.
Download the content
here:
https://github.com/SAP/
com.sap.openSAP.han
a5.templates/raw/maste
r/ex3/user-js.zip
Then import this content
into the user-js folder.

3) The wizard created the
user-js module entry in
the mta.yaml for you;
but now we need to
extend it.
Note: if you don’t want
to type this code, we
recommend that you cut

190

- name: user-js
type: nodejs
path: user-js
provides:
- name: user-js-service
properties:
url: "${default-url}"
requires:

SAP HANA Extended Application Services, Advanced model Development

and paste it from this
web address
https://github.com/SAP/
com.sap.openSAP.han
a5.templates/blob/mast
er/ex3/ex3_12

- name: openSAPHANA5_<group number>-uaa
- name: user-container
- name: user-db

4) Also extend the web
module entry in the
mta.yaml so that it has
routes to the user-js
service as well.
Note: if you don’t want
to type this code, we
recommend that you cut
and paste it from this
web address
https://github.com/SAP/
com.sap.openSAP.han
a5.templates/blob/mast
er/ex3/ex3_13

5) While we are adjusting
for this new module,
you might as well also
extend the xs-app.json
in the web module with
routes for this new
service as well.
Note: if you don’t want
to type this code, we
recommend that you cut
and paste it from this
web address
https://github.com/SAP/
com.sap.openSAP.han
a5.templates/blob/mast
er/ex3/ex3_14
6) Create another OData
service named
user2.xsodata for
UserData.User in the
user-js/lib/user/xsodata
folder. This time, also
link the create operation
to the Server Side
JavaScript Library
(XSJSLIB)
user.xsjs:usersCreateM

service {
"UserData.User" as "Users"
create using
"user.xsjs:usersCreateMethod.xsjslib::usersCreate";
}

191

we recommend that you cut and paste it from this web address https://github. Advanced model Development ethod.user. Here is the code for this file. dot-notation: 0.Details[0].han a5. /** @param {connection} Connection . Note: if you don’t want to type this code.Email)){ throw "Invalid email for " + User.session. //Get Input New Record Values var pStmt = param. //Validate Email if(!validateEmail(User.Details[0]. no-unused-vars: 0.templates/blob/mast er/ex3/ex3_16 /*eslint no-console: 0.com/SAP/ com.sap. no-use-before-define: 0.openSAP.xsj slib. no-redeclare: 0*/ "use strict". "session").xsjs.xsjslib and the function usersCreate.templates/blob/mast er/ex3/ex3_15 7) In the userjs/lib/user/xsjs folder create the file usersCreateMethod. we recommend that you cut and paste it from this web address https://github.SAP HANA Extended Application Services.recordSetToJSON(pStmt. $. var SESSIONINFO = $.afterTableName.executeQuery().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){ var after = param. var User = SESSIONINFO.han a5.prepareStatement("select * from \"" + after + "\""). Note: if you don’t want to type this code.com/SAP/ com.Details[0]. pStmt.The SQL connection used in the OData request @param {beforeTableName} String . } //Get Next Personnel Number 192 .close().import("user.Email + " has problems".xsjs".openSAP.FirstName + " No Way! E-Mail must be valid and " + User. "Details").connection.sap. This will be the exit code that performs validation before the insert of the new record.

"").Details[0].connection.prepareStatement("insert into \"" + after + "\" values(?. pStmt.setString(3. pStmt.setString(2. }else{ pStmt = param.[0-9]{1. } } function validateEmail(email) { var re = /^(([^<>()[\]\\.Details[0]. i++){ var pStmt.executeUpdate(). while (rs.?. pStmt = param.NEXTVAL from dummy").+\"))@((\[[09]{1.xso data/Users/?$format=js on Unfortunately it’s much more complicated to test Create/Update/Delete methods from the browser as they create other HTTP verbs.prepareStatement("TRUNCATE TABLE \"" + after + "\"" ). pStmt.toString()). User.LastName. } 8) Save and run the userjs and then the web module.:\s@\"]+)*)|(\".connection. return re.?.connection.prepareStatement("select \"userSeqId\".?. var rs = pStmt. User.prepareStatement("insert into \"UserData. //Insert Record into DB Table and Temp Output Table for( var i = 0. } pStmt.[0-9]{1.test(email).[^<>()[\]\\.?.}))$/. pStmt.getString(1).close(). } pStmt.close().3}\.User\" values(?. var PersNo = ""..toString()).executeUpdate().toString()). Change the URL to /user/xsodata/user2..3}\])|(([a-zA-Z\-0-9]+\.setString(5.[0-9]{1.3}\.setString(4. User.next()) { PersNo = rs.3}\.?.?)" ).?)" ).FirstName. 193 .SAP HANA Extended Application Services. pStmt.Email.executeQuery(). i<2. pStmt.setString(1. Advanced model Development pStmt = param. PersNo.:\s@\"]+(\..close(). pStmt.?.connection.toString()).. pStmt.Details[0].)+[a-zA-Z]{2. if(i<1){ pStmt = param.

Advanced model Development Later we will revisit this service and build a user interface which can call this service in order to fully test it. EXERCISE 4 – SAPUI5 USER INTERFACE Objective For this exercise we will build a proper SAPUI5 user interface that consumes both the XSJS and XSODATA services from our Node.SAP HANA Extended Application Services. Exercise Description 194 .js module.

Advanced model Development  SAPUI5 Entry Point  SAPUI5 Component  SAPUI5 Views  SAPUI5 Controllers 195 .SAP HANA Extended Application Services.

com/SAP/com.1: SAPUI5 as an XSA Micro-Service Explanation 1.yaml and define a resource for the UI5 central service. In Exercise 1 a simple SAPUI5 Hello World application was generated for us by the module creation wizard.hana5. Note: if you don’t want to type this code.s ap. we recommend that you cut and paste it from this web address https://github. Let’s now adjust our project and this index.openSAP. However a recent addition to XSA was to deliver SAPUI5 as its own Micro-Service for local consumption. The boostrap for SAPUI5 points the publically hosted UI5 library. Let’s begin in the mta.html hello world example to use the local SAPUI5 Micro-service.SAP HANA Extended Application Services. Note if your HANA system doesn’t yet contain this SAPUI5 micro-service then you can skip this exercise continue to use the public SAPUI5 location in subsequent exercises. Advanced model Development EXERCISE 4 – SOLUTION Exercise 4.templates/ blob/master/ex4/ex4_1 196 Screenshot . 2.

SAP HANA Extended Application Services.openSAP. For this we need to add a route configuration to our xsapp. We don’t want to hard code the url of the UI5 service in th bootstrap in every html file in our project.name: user-js-service group: destinations properties: name: user-backend url: ~{url} forwardAuthToken: true 4. we recommend that you cut and paste it from this web address https://github.name: core-js-service group: destinations properties: name: core-backend url: ~{url} forwardAuthToken: true .com/SAP/com.name: web type: html5 path: web requires: .html file in the web/resources folder to use this ui5liburl placholder variable instead of the external address for the UI5 library in the bootstrap. Note: if you don’t want to type this code. we recommend that you cut and paste it from this 197 .json in the web module.openSAP.hana5. Advanced model Development 3. The final step is to adjust the index.name: openSAPHANA5_00-uaa . We can instead use the replacment logic of the App Router to insert the runtime URL for us dynamically.s ap. Next you need to add the UI5 resoruce as a dependency in the web module.templates/ blob/master/ex4/ex4_2 . we recommend that you cut and paste it from this web address https://github.com/SAP/com. Note: if you don’t want to type this code. Note: if you don’t want to type this code.name: ui5-lib properties: ui5liburl: ~{url} .hana5.templates/ blob/master/ex4/ex4_3 5.s ap.

Run the Web module. 7.SAP HANA Extended Application Services.html should load as normal. Save any open files.hana5. 198 . If the change was sucessful.com/SAP/com.s ap. the hello world index.templates/ blob/master/ex4/ex4_4 6. Advanced model Development web address https://github.openSAP. If you would like to confirm the change you can perform a view source in the web browser or use browser developer tools to view the request.

require("jquery.sap. 2) Create a new folder within your web/resoruces folder called i18n. 5) Go to the index. var oBundle = jQuery. var sLocale = sap. Add the following lines just before the myButton creation.sap./i18n/messagebundle. However in real applications. Now we will adjust the HelloWorld application to use a text bundle.getCore(). text strings should be maintained separately so they can easily be translated.html. Save the file. 4) Add the following text to this file.getLanguage().SAP HANA Extended Application Services.properties.ui.resources({url : ". locale: sLocale}).2: Creating a Text Bundle Explanation Screenshot 1) In most of these exercises we will simply hard code our texts to keep everything simple. 3) In this folder create a file named messagebundle.properties". /*************** Language Resource Loader *************/ jQuery.sap.resources"). Advanced model Development Exercise 4. 199 .getConfiguration().

SAP HANA Extended Application Services. Save and re-run your web module.properti es with the shown translated text for the helloworld id. Advanced model Development 6) Your index. 200 . 9) You can return to your project and create a second file in your i18n folder named messagebundle_de.html now looks like this: 7) Change the setText function of the button to use the text bundle.setText(oBund le. The new Hello World text should appear.getText("helloworld ")). myButton. 8) Save and run your web module.

SAP HANA Extended Application Services. Advanced model Development 10) You can change your browser settings so that German is now the primary language. 11) The test page will now automatically show the translated German text. 201 .

SAP HANA Extended Application Services.core. user-scalable=no" /> <title>Workshop OData Test</title> <link type="image/x-icon" href="./odataView"}' data-sap-ui-libs="sap./common/error.js" --> <script id="sap-ui-bootstrap" src="{{{ui5liburl}}}/resources/sap-ui-core. Advanced model Development Exercise 4. <!DOCTYPE html> <html> <head> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width. 202 .hana.ico" rel="icon"> <!-. sap.com/resources/sap-uicore./".openSAP.3: SAPUI5 User Interface Explanation Screenshot 1.js" ></script> <script> new sap.html page. "odataView": ".ico" rel="shortcut icon"> <link type="image/x-icon" href=". app : new sap.templates/ blob/master/ex4/ex4_5 We are loading the SAPUI5 bootstap and then initializing the Fiori shell./images/favicon. Note: if you don’t want to type this code. Here is the complete coding of the odataTest. initial-scale=1.odataTest": ".Shell({ title: "Test App".odataTest".0. we recommend that you cut and paste it from this web address https://github. maximum-scale=1. Let’s return to our web module and create a new html file in the resources folder called odataTest.html 2.m.<script id="sap-ui-bootstrap" src="https://sapui5.ComponentContainer({ name : "opensap.js" data-sap-ui-theme="sap_bluecrystal" data-sap-ui-xx-bindingSyntax="complex" data-sap-ui-resourceroots='{ "opensap.ondemand.hana5.ui.me"> </script> <script type="text/javascript" src="./images/favicon.s ap. Now we want to build a proper SAPUI5 interface that will consume our XSJS and XSODATA services.m.0.com/SAP/com.

js for producing error messages.ajaxSetup({ beforeSend: function(xhr. function getCSRFToken() { var token = null.href = loginPage + "?x-sap-originlocation=" + encodeURIComponent(window. complete: function(xhr.js Note: if you don’t want to type this code. no-unused-vars: 0.location.templates/ blob/master/ex4/ex4_6 /*eslint no-console: 0.settings) { if (settings && settings.s ap.hana5. } } }). no-use-beforedefine: 0.pathname).setRequestHeader("X-CSRF-Token".hasOwnProperty("type") && settings.placeAt("content"). Here is the coding of csrf.openSAP.getResponseHeader("x-saplogin-page"). There are two utility JavaScript libraries we reference in this html page – common/csrf.textStatus) { var loginPage = xhr.com/SAP/com. we recommend that you cut and paste it from this web address https://github. height: "100%" }) }). 4. if (loginPage) { location. </script> </head> <body class="sapUiBody" role="application"> <div id="content"></div> </body> </html> 3. $. xhr.js for the handling of CSRF tokens and common/error.SAP HANA Extended Application Services.type !== "GET"){ var token = getCSRFToken().ajax({ 203 . no-redeclare: 0*/ $. Create a common folder in resources and add these two files. token). } }. Advanced model Development width: "100%".

ERROR.Action.OK]. 204 . Here is the coding of error. type: "GET". async: false.setBusy(false).status === 500 || jqXHR. errorThrown) { var page = sap.xsjs".m. } }).ERROR.responseText.js Note: if you don’t want to type this code. title: "Service Call Error". beforeSend: function(xhr) { xhr. we recommend that you cut and paste it from this web address https://github.ui. sap.show(jqXHR.m. styleClass: "sapUiSizeCompact" }). return.ERROR.MessageBox. }. } else { sap.parse(jqXHR.SAP HANA Extended Application Services.MessageBox. actions: [sap.m. } else { if (jqXHR.MessageBox.getCore().DETAIL.setRequestHeader("X-CSRF-Token".status === "undefined") { var errorRes = JSON. { icon: sap.show(jqXHR. if (typeof jqXHR. no-redeclare: 0*/ function onErrorCall(jqXHR.hana5. no-use-beforedefine: 0.m.statusText.innererror.MessageBox.MessageBox.show( errorRes.Action.s ap.body).getResponseHeader("X-CSRFToken"). page. "Fetch"). textStatus.OK]. return token. { icon: sap. title: "Service Call Error".templates/ blob/master/ex4/ex4_7 /*eslint no-console: 0.openSAP.m.byId("pageID").m. complete: function(xhr) { token = xhr.MessageBox. styleClass: "sapUiSizeCompact" }). actions: [sap.response. title: "Service Call Error".m.MessageBox.error.errordetail.Icon. } 5. { icon: sap.m.Icon. Advanced model Development url: "/xsjs/csrf.com/SAP/com. no-unused-vars: 0.MessageBox.Icon.status === 400) { sap.

styleClass: "sapUiSizeCompact" }). return. but if you want you can create an images folder inside resources and then upload these images from: https://github. no-use-beforedefine: 0.odataTest.Component").model.ui.odataTest. return. actions: [sap.com/SAP/com. Next we need to create our Component.tem plates/raw/master/ex4/favic on.sap. Here is the coding of this file. var model = new sap. sap.hana5.m.declare("opensap.js file in web/resources.ui. sap. { icon: sap.m. jQuery.UIComponent.com/SAP/co m.m.setModel(model).MessageBox. styleClass: "sapUiSizeCompact" }).JSONModel({}).tem plates/raw/master/ex4/sap_ 18.getCore().SAP HANA Extended Application Services. no-unused-vars: 0.openSAP.hana5.Icon.sap.m.show("Bad Entity Definition".require("sap.openSAP.OK].ERROR.MessageBox.MessageBox.png 7.m.Compo nent".require("sap.sap.json.hana5. no-redeclare: 0*/ jQuery. we recommend that you cut and paste it from this web address https://github.ui.MessageToast").Action. 205 .Action.openSAP.MessageBox.templates/ blob/master/ex4/ex4_8 Here we initialize the SAPUI5 component and in doing so we /*eslint no-console: 0. } } } function oDataFailed(oControlEvent) { sap. We also reference some images in this html page. } 6.json.core.MessageBox"). title: "OData Service Call Error".com/SAP/co m.s ap.ico https://github.JSONModel({}).extend("opensap. { init: function() { jQuery.sap.model. Note: if you don’t want to type this code.OK]. They aren’t critical.sap.ui.m. var oConfig = new sap. Advanced model Development actions: [sap.

i < myJSON.setModel(sap. type: "XML".ajax({ url: aUrl.App". var oView = sap.session. myJSON. method: "GET". var page = new sap.prototype.ui.setProperty("/UserName". title: "Workshop OData Test". getSessionInfo: function() { var aUrl = "/xsjs/exercisesMaster. }.UIComponent.ui. { title: "Workshop CDS and OData Test". viewName: "odataView.getCore(). i++) { var config = sap. sap. "config").getModel( "config"). content: oView }). Finally you see that we make a call to xsjs/exercisesMaster.ui.xsjs?cmd=getSessionInfo".getModel()). return page.ui. showHeader: false.onLoadSession( JSON.getModel("config"). 206 . oView. createContent: function() { var settings = { ID: "App". dataType: "json". }.xsjs to fill the page header with the current user id.getCore(). viewData: settings }).SAP HANA Extended Application Services.getCore().getCore().ui. }.getSessionInfo(). Advanced model Development create an instance of the json configuration model.parse(jQuery. onLoadSession: function(myJSON) { for (var i = 0. this.setModel(sap.ui.setBusyIndicatorDelay(10). page.session[i]. arguments).responseText)).core. oView.Page("pageID". this.init.setModel(oConfig.m.view({ id: "App". "config"). description: "Workshop OData Test" }.apply( this. config. sap. async: false }).length. We also load our first view which we will create in the next step.UserName).

ui.ui. Advanced model Development } } }).view. 8. 10. Create a folder called odataView inside resources. This is where we will hold all of our views and controllers.xml. we recommend that you cut and paste it from this web address https://github.fragment. Here is the complete coding of this file.App" xmlns="sap.m"> <Panel expandable="true" expanded="true" headerText="Multi-Entity Service Selections"> <List width="100%"> 207 .unified" xmlns:mvc="sap.png"> <u:user> <u:ShellHeadUserItem image="sapicon://person-placeholder" username="{config>/UserName}"/> </u:user> <u:content> <IconTabBar class="iconTabBarPaddingTop" upperCase="true" expanded="true"> <items> <IconTabFilter text="Multi-Entity Read"> <core:Fragment fragmentName="odataView./images/sap_18.xml.hana5.ui. Create a file named MRead. but then defers the design of the header and table areas to an XML fragment we will create next. Note: if you don’t want to type this code.mvc" xmlns:core="sap.core" xmlns="sap.s ap. Create the root view named App.com/SAP/com.ui.view.templates/ blob/master/ex4/ex4_9 It creates the shell control and the overall flow of our page. <core:View controllerName="odataView.SAP HANA Extended Application Services. Here is the complete coding of the App.core"> <u:Shell id="myShell" icon=".xml file.core.openSAP.m" xmlns:u="sap. 9.MRead" type="XML"/> </IconTabFilter> </items> </IconTabBar> </u:content> </u:Shell> </core:View> <core:FragmentDefinition xmlns:core="sap.

com/SAP/com. The rendering of these two sections if further separated out into two JavaScript based fragments.MTableHead" type="JS"/> <core:Fragment fragmentName="odataView.fragment. Note: if you don’t want to type this code.SAP HANA Extended Application Services. Advanced model Development Note: if you don’t want to type this code. We then will have a table control for our purchase order header and another for our purchase order item.m"> <Panel headerText="PO Item Data" expandable="true" expanded="true"> <content> <Table id="tblPOItem" growingThreshold="5" growing="true"/> </content> </Panel> </core:FragmentDefinition> .templates/ blob/master/ex4/ex4_12 208 <core:FragmentDefinition xmlns:core="sap. Filename MTableItem.templates/ blob/master/ex4/ex4_11 <InputListItem label="Service Path"> <Input id="mPath" value="{/mPath}"/> </InputListItem> <InputListItem label="Header Entity Name"> <Input id="mEntity1" value="{/mEntity1}"/> </InputListItem> <InputListItem label="Item Entity Name"> <Input id="mEntity2" value="{/mEntity2}"/> </InputListItem> </List> <Button press="callMultiService" text="Execute Service"/> <Button press="callExcel" text="Download Excel"/> </Panel> <core:Fragment fragmentName="odataView.hana5.core" xmlns="sap.xml file.xml. Note: if you don’t want to type this code.fragment.hana5.ui.openSAP.com/SAP/com.Create the MTableHead.core" xmlns="sap.hana5.s ap.s ap.ui. Here is the complete coding for this file.MTableItem" type="JS"/> </core:FragmentDefinition> <core:FragmentDefinition xmlns:core="sap. we recommend that you cut and paste it from this web address https://github.s ap.com/SAP/com. we recommend that you cut and paste it from this web address https://github. 11.openSAP. 12.openSAP.templates/ blob/master/ex4/ex4_10 Here we build panel with our input fields.Repeat the process for the PO Item table. These fields will allow us to control settings for calling our XSODATA service. we recommend that you cut and paste it from this web address https://github.m"> <Panel headerText="PO Header Data" expandable="true" expanded="true"> <content> <Table id="tblPOHeader" rowSelectionChange="onRowSelect" growingThreshold="5" growing="true"/> </content> </Panel> </core:FragmentDefinition> We are creating a table control to display our Purchase Order Header data which will be returned by the XSODATA service.

openSAP. Note: if you don’t want to type this code. oTable.getCore(). urlMulti). "/POItem").ui. var urlMulti = "/xsodata/purchaseOrder.getProperty("/mPath").App". var mEntity2 = sap.getCore().getCore(). no-use-beforedefine: 0.m.removeAllItems(). no-redeclare: 0.getProperty("/mEntity1"). // make everything inside this View appear in Compact mode var userName = sap. sap.com/SAP/com.setProperty("/mEntity1". "/POHeader").hana5.getModel().byId("tblPOItem").ui.removeAllColumns().ui.ui.m.getCore().model.js sap.getCore().getModel(). sap.getServiceMetadata().controller.ColumnListItem(). true).getCore(). We set some initial values into configuration model so they appear in our input fields.getModel().ui.byId("tblPOHeader"). oModel. Advanced model Development 13.xsodata".ui. var mEntity1 = sap.removeAllColumns().byId("App"). var oModel = new sap. We start with the onInit event which fires on startup of the page.templates/ blob/master/ex4/ex4_13 There is some considerable code in this file because here we have all the event handlers for our application.setProperty("/mPath". we recommend that you cut and paste it from this web address https://github.ui.ui. no-undef: 0*/ //To use a javascript controller its name must end with . var mPath = sap. oTable. oTableItem. callMultiService handles the logic to call our OData service. onRowSelect handles the selection of a PO Header record and forces the loading of the corresponding PO Item records.ColumnListItem(). callMultiService: function() { var oTable = sap.ui.odata.xsjs to download our PO data in a text tab delimited format.getModel("config").getModel().ui.setProperty("/mEntity2". no-unused-vars: 0. oDataFailed). sap. /*eslint no-console: 0.getProperty("/mEntity2"). { onInit: function() { this. var oControl.getProperty("/UserName").js.ODataModel(mPath.attachEvent("requestFailed". if (!oMeta) { 209 .byId("App").getModel(). Finally callExcel responds to a button press and calls /xsjs/hdb. var columnList = new sap.controller. var oMeta = oModel.removeAllItems().getCore().addStyleClass("sapUiSizeCompact").ui.s ap.getView().getCore(). oTableItem. var columnListItem = new sap. }.controller("odataView.SAP HANA Extended Application Services.getModel(). var oTableItem = sap.The final piece of our UI is the view controller named App.getCore(). We are reading the metadata from the OData service in order to dynamically create the columns in our table controls.

m.show("Bad Service Definition".property.name }.m.entityType[0].Icon. actions: [sap.name }).addCell(new sap. Advanced model Development sap. columnListItem. i < oMeta.MessageBox.addCell(new sap.MessageBox.addColumn(new sap. styleClass: "sapUiSizeCompact" }). columnList. oTableItem.dataServices. for (var i = 0.ERROR.Label({ text: property.property[i].entityType[1].m. { icon: sap.addColumn(new sap.Text({ text: { 210 .dataServices.property.dataServices.m.SAP HANA Extended Application Services.Column({ header: new sap.m.schema[0]. i < oMeta.property[i]. name: property.m.Action.MessageBox. } else { //Table Column Definitions for (var i = 0.name }).schema[0]. i++) { var property = oMeta.m. oTable.m.entityType[1].Label({ text: property.Text({ text: { path: property.name })).dataServices.m.schema[0]. i++) { var property = oMeta. width: "125px" })). } oTable. width: "125px" })).setModel(oModel).entityType[0].length.Column({ header: new sap.length.schema[0]. title: "Service Call Error".OK].

callExcel: function(oEvent) { //Excel Download window.name }.SAP HANA Extended Application Services.So now run the web module.getModel().getCore(). 211 .byId("val2_2"). oTableItem.getProperty("PURCHASEORDERID".setModel(oModel). name: property.getCore().bindItems(ContextItem). } oTable. }.byId("tblPOItem"). 14. template: columnList }).xsjs"). oTable.bindItems({ path: mEntity2.getSource(). var oTableItems = sap. It will need to rebuild and redeploy all the newly added artifacts.getValue() + "(PURCHASEORDERID='" + poId + "')" + sap. var poId = data.ui.getSource(). } }).getSelectedIndex())).byId("val2_3"). template: columnListItem }). var ContextItem = sap. oTableItems.ui.ui. }. onRowSelect: function(oEvent) { var data = oEvent. return. } oTableItem.getCore().getValue().name })). var oTable = oEvent.getContextByIndex(oTable. Advanced model Development path: property.open("/xsjs/hdb.bindItems({ path: mEntity1.

html from earlier. Advanced model Development 15.SAP HANA Extended Application Services. you should see the index.html to test the new UI we just created. 212 . Test both the Execute Service and Download Excel buttons. Change this to odataTest.In the running tab.

html. Component.view.ui.ondemand. maximum-scale=1. user-scalable=no" /> <title>XSJS Multiply Exercise</title> <link type="image/x-icon" href="/images/favicon. It loads the UI5 boostrap and creates the intial shell UI structure. Note: You might have to adjust the sap-ui-boostrap URL if your system doesn’t have the SAPUI5 central service installed If you need help writing this code please refer to the solution at: https://github.xml. </script> </head> <body class="sapUiBody" role="application"> <div id="content"></div> </body> </html> 213 . App.js.xsjsMultiply" }) }).0.com/resources/sap-ui-core.com/SAP/com .html is nearly identical to our earlier exercise./". view folder.hana.SAP HANA Extended Application Services. "view": ".me"> </script> <script> new sap.xsjsMultiply": ".ico" rel="icon"> <!-.openSAP.placeAt("content").ComponentContainer({ name : "sap.sap.controller.m.shineNext. sap.Shell({ app : new sap.js" --> <script id="sap-ui-bootstrap" src="{{{ui5liburl}}}/resources/sap-uicore.templ ates/blob/master/ex4/ex4_1 4 <!DOCTYPE html> <html> <head> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width. and App.m.xml) 2) The index.core.js" data-sap-ui-theme="sap_bluecrystal" data-sap-ui-xxbindingSyntax="complex" data-sap-ui-resourceroots='{ "sap.hana5.<script id="sap-ui-bootstrap" src="https://sapui5.4: Consume XSJS Services via JQuery AJAX calls Explanation Screenshot 1) Using what you have learned create a new folder named multiply in web/resources with a similar structure to the earlier applications you created (index.shineNext. Advanced model Development Exercise 4./view" }' data-sap-ui-libs="sap.ico" rel="shortcut icon"> <link type="image/x-icon" href="/images/favicon.0. initial-scale=1.

ui. Note: of course you could perform simple math on the client side. { If you need help writing this code please refer to the solution at: init: function(){ jQuery.Component". viewData: settings }). return oView.m. createContent: function() { var settings = { ID: "xsjsMultiply". It has two input fields for the numeric values which are multiplied.init.Component"). We will then call the service on the server when the user changes the value in either field.sap.App" xmlns="sap. type: "XML".ui.hana5.m" xmlns:mvc="sap.com/SAP/com 214 <core:View controllerName="view.Multiplication" expandable="true" expanded="true"> <List width = "400px"> <InputListItem label="Value #1"> <Input id="val1" value="{/val1}" liveChange="onLiveChange" /> </InputListItem> . 4) The complete View Implementation is provided for you as a template.require("sap. although simplier.SAP HANA Extended Application Services.sap.require("sap.ui. https://github. title: "XSJS Multiply Exercise".sap.ui.sap.UIComponent. jQuery. arguments). sap. The template can be accessed at: https://github.MessageToast").core" > <Panel headerText="XS Service Test .prototype.declare("sap.openSAP.templ ates/blob/master/ex4/ex4_1 5 }. } }).xsjsMultiply. We are using this very simple example in order to focus on the techniques for creating and calling the XSJS services without needing to get into too much detail.view({ id: "app". viewName: "view.extend("sap. jQuery.apply(this. var oView = sap.UIComponent.App".core.mvc" xmlns:core="sap.js is also very similiar.shineNext.core.xsjsMultiply. than our eariler exericse.com/SAP/com . sap. Advanced model Development 3) The Component.core.MessageBox").shineNext. description: "SHINE XSJS Multiply Exercise" }.ui.m.

templ ates/blob/master/ex4/ex4_1 6 5) In the controller add the onInit function with code to create local JSON model. { onInit: function() { var model = new sap.JSONModel({}).getView(). this.addStyleClass("sapUiSizeCompact").model.controller("view.ui.setModel(model).App".json.SAP HANA Extended Application Services. 215 . Advanced model Development .hana5. You can also set the Compact design.getView().ui.openSAP.sap. <InputListItem label="Value #2"> <Input id="val2" value="{/val2}" liveChange="onLiveChange" /> </InputListItem> <InputListItem label="="> <Text id="result" value="{/result}" /> </InputListItem> </List> </Panel> </core:View> sap. this. // make everything inside this View appear in Compact mode }.

format. jQuery.com/SAP/com .core. This will field will contain the result of the multiplication in clear text. accept the response object as an input parameter called myTxt.getParameters(). minFractionDigits: 0.sap.NumberF ormat to format the output as an interger and set the value back into the oResult textView.setText(oNumberFormat. This is the event which is triggered every time the value is changed in either input field. Use the sap.hana5.getCore(). }.getModel(). } else { valSend = result. . On Success of the AJAX call.ui.val2.sap.xsjs?cmd=mult iply" + "&num1=" + escape(oEvent. } }. error: controller. groupingEnabled: true }). success: controller. var result = view.getView(). If you need help writing this code please refer to the solution at: https://github.getView(). Advanced model Development 6) In the controller add an event handler called onLiveChange which has two parameters – oEvent and oVal. If you need help writing this code please refer to the solution at: onLiveChange: function(oEvent) { var view = this. if (oEvent.id === "app--val1") { valSend = result.onCompleteMultiply. If there is a failure call a controller event named onErrorCall.format.templ 216 onCompleteMultiply: function(myTxt) { var oResult = sap. } else { jQuery.ajax({ url: aUrl.ui.hana5. } var aUrl = "/sap/hana/democontent/epm/services/multiply.core.sap. } if (valSend === undefined) { valSend = 0.byId("app-result").ui.getController().getIntegerInstance({ maxFractionDigits: 12.getData().com/SAP/com .openSAP.newValue) + "&num2=" + escape(valSend).SAP HANA Extended Application Services. https://github.val1.ui.format.format(myTxt)). if (myTxt === undefined) { oResult. var controller = this.onErrorCall }). oResult. Using jQuery.openSAP.core. var valSend.setText(0).ajax call the URL /workshop/solution/services/ multiply. var oNumberFormat = sap.getParameters().NumberFormat").NumberFormat.require("sap. dataType: "json".templ ates/blob/master/ex4/ex4_1 7 7) In the onCompleteMultiply. method: "GET".xsjs?cmd=multiply adding on the num1 value from the oEvent and num2 value from the oVal input parameter. call a controller event named onCompleteMultiply.

Message Box. https://github.openSAP.com/SAP/com .responseText as the details of this error.alert("Invalid Input Value").m.ui.m. } else { sap.alert(jqXHR. The URL would be /multiply/. you only need to start typing into either field to trigger the call to the server and the calculation of the results 217 . If you need help writing this code please refer to the solution at: } }).commons. produce an error dialog (sap.responseText).responseText === "NaN") { sap.templ ates/blob/master/ex4/ex4_1 9 9) Save your project.show) and output the jqXHR.MessageBox. 8) In the onErrorCall. } return. Test your application in a web browser by runnign the web module.hana5. Since we are using the live change event on the input fields. Advanced model Development ates/blob/master/ex4/ex4_1 8 onErrorCall: function(jqXHR) { if (jqXHR.MessageBox.SAP HANA Extended Application Services.sap.

com/resources/sap-ui-core.0.js" data-sap-ui-theme="sap_bluecrystal" data-sap-ui-xx-bindingSyntax="complex" data-sap-ui-resourceroots='{ "opensap. create two files – one named Component.hana.5: Consume a Basic OData Service within UI5 binding the service to a Table Explanation Screenshot 1) Create a folder named odataBasic within the web/resources folder 2) Within this folder. . 4) To avoid having to do too much typing.js and App.SAP HANA Extended Application Services.view. In the index./". maximum-scale=1.ico" rel="icon"> <!-.js" --> <script id="sap-ui-bootstrap" src="{{{ui5liburl}}}/resources/sap-uicore. Advanced model Development Exercise 4.html. we have prepared some template code for you. This page will create a single html content item and then start the Component.0. Also create a sub-folder named view.<script id="sap-ui-bootstrap" src="https://sapui5.js and one named index. user-scalable=no" /> <title>OData Basic Exercise</title> <link type="image/x-icon" href="/images/favicon.js. initial-scale=1.js file which contains the rest of the true application startup logic.odataBasic": ". 3) Within the view folder you just created. Note: You might have to adjust the sap-ui-boostrap URL if your system doesn’t have the SAPUI5 central service installed 218 <!DOCTYPE html> <html> <head> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width.ondemand.html we need to insert the basic UI5 bootstrap and initialization code.ico" rel="shortcut icon"> <link type="image/x-icon" href="/images/favicon.controller. please now create two files – App.

} }).m.odataBasic" }) }).App".declare("opensap. 6) Since this is a simple example application we won’t need any controller logic.js file we initialize the application and set the base UI elements for the page. var oView = sap.templ ates/blob/master/ex4/ex4_2 1 createContent: function() { //To-Do: Insert Model Here var settings = { ID: "odataBasic".odataBasic.templ ates/blob/master/ex4/ex4_2 0 new sap.core.hana5. These are the most important parts and will be completed in the next few steps.placeAt("content")./view" }' data-sap-ui-libs="sap.controller("opensap.com/SAP/com .core.hana5.SAP HANA Extended Application Services.Component").view.com/SAP/com . /*eslint no-undef: 0*/ jQuery.{ }).sap.ui. sap.me"> </script> We recommend that you cut and paste it from this web address <script> https://github.Component". { We recommend that you cut and paste it from this web address https://github.ui. viewData: settings }). viewName: "opensap.UIComponent.setModel(oModel. title: "OData Basic Exercise". Advanced model Development "view": ".m.extend("opensap.view.App". description: "SHINE service for OData Basic Exercise" }.odataBasic.openSAP.odataBasic.ComponentContainer({ name : "opensap. return oView. Just insert this empty controller logic sap.ui.odataBasic.openSAP.sap.Shell({ app : new sap. oView.view({ id: "app". You should notice that there are commented To-Do sections in this code which you just copied into the file. "bpModel"). </script> </head> <body class="sapUiBody" role="application"> <div id="content"></div> </body> </html> 5) In the Component.sap. sap. type: "JS".ui. 219 .

m. we have prepared some template code for you which already has the definition of the table UI element and the table columns. oTable. // make everything inside this View appear in Compact mode var oTable = new sap.m.openSAP.view.view. /*eslint no-unused-vars: 0*/ sap.templ ates/blob/master/ex4/ex4_2 2 You should notice that there are commented To-Do sections in this code which you just copied into the file.m. width: "125px" })).odataBasic. growingThreshold: 10. //To-Do: Connect model to table and bind and sort //Table Column Definitions //Table Column Definitions oTable. columnList.Column({ header: new sap. 220 .js file: Note: if you don’t want to type this code.sap. columnList. These are the most important parts and will be completed in the next few steps.addColumn(new sap. name: "EMAILADDRESS" })).App".Label({ text: "Email Address" }).ColumnListItem(). width: "125px" })). growing: true }).jsview("opensap.Label({ text: "Partner ID" }).Table("bpTable". You can cut and paste this template code from this address into the odataBasic.Label({ text: "Phone Number" }).m.addColumn(new sap.m. but none of the logic to consume the OData service.m.addCell(new sap.SAP HANA Extended Application Services.com/SAP/com .addStyleClass("sapUiSizeCompact"). oTable. Advanced model Development 7) For the view definition to avoid having to do too much typing.odataBasic.m.hana5.addCell(new sap.m.Column({ header: new sap.view.Text({ text: { path: "bpModel>EMAILADDRESS" }. var columnList = new sap. name: "PARTNERID" })). { tableId: "bpTable".App".m. { getControllerName: function() { return "opensap. createContent: function(oController) { this.Text({ text: { path: "bpModel>PARTNERID" }. }.addColumn(new sap.Column({ header: new sap.m.ui. we recommend that you cut and paste it from this web address https://github.

m.m. name: "LEGALFORM" })).SAP HANA Extended Application Services.m.addCell(new sap.addColumn(new sap. columnList. name: "FAXNUMBER" })). columnList. name: "CURRENCY" })).Column({ header: new sap. width: "125px" 221 .addCell(new sap. name: "PHONENUMBER" })). oTable. oTable. oTable. oTable.Text({ text: { path: "bpModel>FAXNUMBER" }.m.Text({ text: { path: "bpModel>LEGALFORM" }.Column({ header: new sap.addColumn(new sap.Text({ text: { path: "bpModel>CURRENCY" }. width: "125px" })). width: "125px" })).m.m.m.addColumn(new sap.addColumn(new sap.Label({ text: "Currency" }).m.m. width: "125px" })).Column({ header: new sap. Advanced model Development width: "125px" })).Label({ text: "Fax Number" }).Text({ text: { path: "bpModel>PHONENUMBER" }.Label({ text: "Web Address" }).addCell(new sap. columnList.Column({ header: new sap.addCell(new sap.Label({ text: "Legal Form" }). columnList.m.m.m.

model.model.setExpandable(true).setModel(oModel.Link({ text: { path: "bpModel>WEBADDRESS" }.ui.addCell(new sap. target: "_blank".getCore(). var oModel = new sap.ui. displayPanel.odata. href: { path: "bpModel>WEBADDRESS" }. var displayPanel = new sap.ui.js file.odata. true). sap. 222 .ODataModel("/xsodata/businessPartners.SAP HANA Extended Application Services. "bpModel"). xsodata/. displayPanel. name: "WEBADDRESS" })). 8) In the first To-Do location in the Component.Panel("dispPanel").setExpanded(true). Use the provided service /xsodata/businessPartners. return displayPanel.m.m. Advanced model Development })).addContent(oTable).setHeaderText("Business Partner Details"). } }).ODataM odel. displayPanel. columnList. you should add the code to create a model object named oModel of type sap.x sodata/".

run the html5 module. as well as server side scrolling via the various built-in parameters of the OData service framework. var sort1 = new sap. Advanced model Development 9) In the second To-Do location in the App.ui.bindItems({ path: "bpModel>/BusinessPartners".Sorter("PARTNERID"). 223 .js file.ui.SAP HANA Extended Application Services. you should set the model named bpModel to the table control named oTable.Sorter) which uses the column PartnerId. oTable. sorter: sort1 }).model. We get built in table sorting and filtering. Create a sorter (type sap. Save your files. Bind the table to the entity BusinessPartners and add the sorter object to the binding.view. 11) Adjust the run URL to /odataBasic/. template: columnList.model. 10) That’s all that is necessary to connect the Table UI element to the OData service.

entityType[0]. oData services expose all their meta data and we can use this feature to build the columns dynamically.getServiceMetadata(). Advanced model Development Exercise 4. i < oMeta. Return to your view file.length .dataServices.getCore(). for ( var i = 0.property.SAP HANA Extended Application Services. However. Inside this meta data you will find the columns of the service at 224 //Table Column Definitions var oMeta = sap.schema[0].property[i].6: Use oData Metadata to dynamically create the columns. 2) You can create a connection to the metadata object via the function getServiceMetadata of your model object. i++) { var property = oMeta. Explanation Screenshot 1) In the previous part of this exercise we hard coded all the table column definitions in the template. . Delete the complete block of lines after the Table Column Definitions comment and before the var displayPanel line.ui.getModel("bpModel").schema[0].dataServices.entityType[0].

hana5.name })).m. Loop over this collection and create a column for each property.com/SAP/com .Label({ text: property. Notice that you now have all the columns of the service.name }). name: property. columnList. If you need help writing this code please refer to the solution at: https://github.name }. The URL would be /odataBasic.name in the service dynamically.addCell(new sap.Text({ text: { path: "bpModel>"+property.Column({ header: new sap.addColumn(new sap.templ ates/blob/master/ex4/ex4_2 3 } Save and re-run your web module.ent ityType[0]. 3) Test your application in a web browser using the Run option.schema[0]. dataServices. not just the few you had before.openSAP. Advanced model Development oTable.sap.property. width: "125px" })).m.SAP HANA Extended Application Services. 225 .m.

3) In the copy folder dialog.7: Consume an OData Service with Create Option Explanation 1) We will begin by making a copy of the previous exercise 2) Highlight the resources folder and right mouse click. give the new Name as odataCRUD 226 Screenshot . Advanced model Development Exercise 4. Choose Paste.SAP HANA Extended Application Services.

model.App".com/SAP/com .App”) var oView = sap. { createContent: function() { var oParams = {}.UIComponent.getModel("userModel" ). type: "XML".odataBasic. Change the first part of the Component.ODataModel( "/user/xsodata/user2.declare("opensap.odataBasic.Compone nt".setModel(sap.xmlview(“app”.js file to match the code you see here: If you need help writing this code please refer to the solution at: https://github.ui.setModel(oModel.getCore().ui.BindingMode. oView.ui. 5) Also in the Component.ui. var oView = sap. function(oEvent) { sap. viewData: settings }). oModel. oParams.view({ id: "app".v2.defaultBindingMode = sap.extend("opensap.useBatch = false.view.json = true. var settings = { ID: "odataBasic".MessageBox. type: "XML".templ ates/blob/master/ex4/ex4_2 4 /*eslint no-undef: 0*/ jQuery. “view. viewName: "opensap. sap. viewName: "sap.openSAP.TwoWay.js file change the service URL to: /user/xsodata/user2.hana5.odata. }).attachRejectChange(this.odataBasic.view({ id: "app". description: "SHINE service for OData Basic Exercise" }. title: "OData Basic Exercise".view. oParams).xsodata/".m.ui.Component"). oParams. "userModel"). var oModel = new sap.model.SAP HANA Extended Application Services.shineNext.ui. We must also setup the model binding mode.sap.sap.js change the page creation to new sap.xs odata/. "userModel"). oParams. In the Component.ui. viewData: settings }).App". Advanced model Development 4) Much of the startup logic will be the same. } }).defaultUpdateMethod = "PUT". 227 . sap.odataBasic. return oView. oParams.core.ui.getCore().alert("You are already editing another Entry! Please submit or reject your pending changes!").

It also has the ability to update records in the table control.SAP HANA Extended Application Services.view.view.xml file instead. 7) The complete View Implementation for App. this view has input fields for creating a new record.hana5. Advanced model Development 6) Instead of a JavaScript view we are going to use an xml view. Therefore you can delete the App.xml is provided for you as a template. It has a table control built from the odata service /xsodata/user2.openSAP. not just display them.templ ates/blob/master/ex4/ex4_2 5 8) In this exercise we will focus on the implement of the event handlers – which is all done in the App.xsodata/ . 228 .view.js file and then create an App.all of which is very similar to the earlier exercise.controller. In addition. The template can be accessed at: https://github.js file.sap.com/SAP/com .

show("Create successful").LastName.setHeaders({ "content-type": "application/json.charset=utf-8" }). onInit. oEntry. onInit : function(){ var model = new sap. oEntry.SAP HANA Extended Application Services. this. }.onErrorCall. callUserService (which performs the creation of new records) and callUserUpdate (which updates records from the table) and onErrorCall (and error handler).ui.com/SAP/com .create("/Users". Then you can call the model. }. var oEntry = {}. Advanced model Development 9) We need to add to event handlers.JSONModel({}).m.templ 229 .openSAP.getData(). var result = this.MessageToast.success = function() { sap. }. PERS_NO can get a hardcoded value of “0000000000”.getModel(). oEntry. you first need to get access to the model object. 10) For the onInit we need to create an empty JSON model for our input fields and set it into the view.create function for the entity /Users. Next you need to create a JSON object with the service fields (PERS_NO. LASTNAME.getCore().setModel(model).ZMYNEW1 = "".error = this. oModel. callUserService: function() { var oModel = sap. The other fields should be read from the screen with the bound JSON model Finally you need to set a custom header of contenttype with the value of application/json. 11) For callUserService.getView(). If you need help writing this code please refer to the solution at: https://github.FirstName. oEntry.json.sap. oEntry. and E_MAIL).model. var mParams = {}.ui. oEntry.Email.LastName = result. mParams).hana5.getModel("userModel"). mParams. oModel.FirstName = result.getView().Email = result.charset=utf8 in the model. FIRSTNAME.UserId = "0000000000". Insert the empty functions in the controller as shown. mParams.

show("Update successful").error. }.m. callUserUpdate: function() { var oModel = sap.error.response. Advanced model Development ates/blob/master/ex4/ex4_2 6 12) The implementation of callUserUpdate is actually much simplier. If you need help writing this code please refer to the solution at: https://github. onErrorCall: function(oError) { if (oError.MessageBox.alert(errorRes.innererror.sap. } } return.success = function() { sap.error. If you need help writing this code please refer to the solution at: oModel.responseText).alert(errorRes.hana5.show("Update failed").openSAP.MessageToast. mParams.com/SAP/com .MessageBox.submitChanges(mParams).m.message) { sap.openSAP. 230 .sap.getModel("userModel").templ ates/blob/master/ex4/ex4_2 7 13) In the onErrorCall we want to be able to parse the error body to pull out the detailed error message.statusCode === 500 || oError.m.getCore().alert(oError.setHeaders({ "content-type": "application/json.com/SAP/com . } else { if (!errorRes.m.MessageBox.innererror. https://github.MessageToast.toS tring()).parse(oError.mes sage). } else { sap. } else { sap.MessageBox.alert(errorRes.statusText).value) . if (!errorRes. oModel.hana5. mParams.templ ates/blob/master/ex4/ex4_2 8 }. }.innererror.message.SAP HANA Extended Application Services.charset=utf-8" }).error.error = function() { sap. We are using two-way model binding therefore we need only ask the model to submit any pending changes and capture the response status events.error.innererror) { sap. var mParams = {}.statusCode === 400) { var errorRes = JSON.m.ui.m.

} } }). 14) Save your files and re-run the web module. 15) Test your application in a web browser using the Run option. Try creating a new record. The URL would be /odataCRUD/.SAP HANA Extended Application Services. Also try creating a record with an invalid email address. Advanced model Development return. 231 .

SAP HANA Extended Application Services. Advanced model Development 232 .

m" xmlns:core="sap.8: OData Batch Operation Explanation Screenshot 1) Often you might want to send more than one operation to the server at a time.sap. If you need help writing this code please refer to the solution at: https://github.fragment.openSAP. <core:FragmentDefinition xmlns="sap.com/SAP/com .core"> <Dialog title="Create Users with batch request" class="sapUiPopupWithPadding" > <content> </content> <beginButton> <Button text="Submit" press="onSubmitBatch" /> </beginButton> <endButton> <Button text="Cancel" press="onDialogCloseButton" /> </endButton> </Dialog> </core:FragmentDefinition> In this exercise we will extend the odataCRUD project from the previous exercise to allow the creation of multiple records at a time.templ ates/blob/master/ex4/ex4_2 9 233 .hana5. The Odata $batch operation allows this. Add the following code to this file. Create a new file named batchDialog. Advanced model Development Exercise 4.SAP HANA Extended Application Services.xml in the view folder. First we need to create an XML fragment for our batch dialog we will display.ui.

}.SAP HANA Extended Application Services.getController(). press: function() { view. adding of new row. var addIcon = new sap.getView().addContent(view.removeContent(oEvent. Advanced model Development 2) We also need to add a new button in the App. } }).oSource. onDialogCloseButton: function() { this.core. }. view.oParent.getView(). view. color: "#49311c".sap. deleting rows.com/SAP/com ._bDialog.ui. var icon.addStyleClass("sapUiSizeCompact").xml that will trigger the batch creation dialog box._bDialog.addDependent(this.getController(). color: "#006400"._bDialog).controller._bDialog. press: function(oEvent) { view.xmlfragment( "view. getItem: function(isFirstRow) { var view = this.open().Icon({ src: "sap-icon://add". Here we use two feature of the UI5 OData model object._bDialog. 3) Now in the App. view.close(). The OData model takes care of all the technical details of building the multi-part MIME request which will contain all the inner request objects for each record you want to create._bDialog = sap.sId).Icon({ src: "sap-icon://delete". First you use the addBatchChangeOperation s to collect the individual records and the actions you want to perform on the records. var deleteIcon = new sap.getItem(true)). size: "1. size: "1.getView()._bDialog.ui. Next you use submitBatch function to send the request to the server. this // associate controller with the fragment ).hana5. .5rem".core. If you need help writing this code please refer to the solution at: https://github. view.5rem".ui. view.templ ates/blob/master/ex4/ex4_3 0 234 onBatchDialogPress: function() { var view = this.batchDialog". and calling the service in Batch mode. Add the following code to create a button for this.addContent(view. } })._bDialog.js you need to implement the event handlers for the dialog creation.getItem(false)).view.openSAP.

FlexJustifyContent. user. var emailTxt = new sap. }.getView().Input({}).SAP HANA Extended Application Services.ZMYNEW1 = "".getValue(). Advanced model Development if (isFirstRow) { icon = addIcon.UserId = "0000000000". i++) { var user = {}.addStyleClass("iconPadding"). var newUserList = []. lastNameTxt. firstNameInput.length.push(user).Label({ text: "First Name" }). i < content. user. } icon. var lastNameTxt = new sap.m.addStyleClass("alignText").addStyleClass("alignText").Label({ text: "Email" }).FlexBox({ // enableFlexBox: true. lastNameTxt.getItems()[5]. user. } else { icon = deleteIcon. emailTxt. onSubmitBatch: function() { var view = this.Email = content[i]. lastNameInput.m. user. firstNameTxt. return new sap.Input({}).SpaceBetween.getItems()[1]. items: [firstNameTxt. var content = view. var emailInput = new sap. emailInput.FirstName = content[i].getItems()[3]. var firstNameInput = new sap. for (var i = 0. icon ] }).addStyleClass("alignText").m. user. // justifyContent: sap.getValue()._bDialog. var firstNameTxt = new sap. emailTxt.m. // fitContainer: true. var lastNameInput = new sap.m.Input({}). newUserList. } 235 .m.m.getContent().getValue().Label({ text: "Last Name" }).m.LastName = content[i].

for (var k = 0. k++) { batchChanges.MessageToast.length. //submit changes and refresh the table and display message batchModel. newUserList[k])). 236 .submitBatch(function() { var oModel = sap.getController(). }.html file and add several style elements near the beginning of the file.createBatchOperation("/Users".xsodata/". view.refresh(). oModel. } 4) Save your files. 5) Not critical. true).model.getModel("userModel").m. var batchChanges = [].onErrorCall ). k < newUserList.show(k + " users created"). view.addBatchChangeOperations(batchChanges).getCore().ui.ui.SAP HANA Extended Application Services._bDialog.ODataModel("/user/xsodata/userBeforeExit.close().push(batchModel.odata. sap. Advanced model Development //create an array of batch changes and save var batchModel = new sap. } batchModel. "POST". but if you want the field alignment in the batch dialog to look nice. you can also return to the index.

237 . Advanced model Development 6) Test your application in a web browser using the Run option. The URL would be /odataCRUD/.SAP HANA Extended Application Services. Try using the new Create users with batch request button and creating two records.

SAP HANA Extended Application Services, Advanced model Development

Exercise 4.9: OData Deep Insert (Content-ID and Links)
Explanation
1) As we saw in the previous
exercise, it is possible to
perform multiple operations
in one request.
This is particularly useful in
situations where you are
inserting objects with a
parent/child relationship.
But what happens when
you create both objects via
generated keys on the
server side. In one batch
how can you also create the
relationship between the
objects as well? This
exercise will look at how to
perform just such a ‘deep
insert’ in one batch and will
rely upon many of the
techniques covered in
previous exercises.

2) We already have the
XSODATA service named
businessPartnersAddress
es.xsodata in our core-js
module,
lib/sap/hana/democontent/e
pm/services folder. In this
service we want to allow the
creation of records in both
the MD.BusinessPartner
and the MD.Addresses
tables. Also create an
association between the
two tables. Uses XSJS exit
handlers for both tables and
the association.

238

Screenshot

SAP HANA Extended Application Services, Advanced model Development

3) We also have the xsjslib
named
businessPartnersAddresses
for the exit handlers of our
service.

4) We will look at each of the
exit handlers one at a time.
The first function runs
before the creation of the
business partner record and
allows us to use a
sequence for the partner id
and for defaulting in some
values.

$.import("sap.hana.democontent.epmNext.services", "session");
var SESSIONINFO = $.sap.hana.democontent.epmNext.services.session;
/**
@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 bp_create_before_exit(param) {
var
after = param.afterTableName;
var pStmt;
try {
pStmt = param.connection.prepareStatement('select
"businessPartnerId".NEXTVAL from DUMMY');
var rs = pStmt.executeQuery();
var PartnerId = '';
while (rs.next()) {
PartnerId = rs.getString(1);
}
pStmt.close();
pStmt = param.connection.prepareStatement('update "' + after
+ '" set PARTNERID = ?,' +
' PARTNERROLE = ?, ' +
' "HISTORY.CREATEDBY.EMPLOYEEID" =
?,' +
' "HISTORY.CHANGEDBY.EMPLOYEEID"
= ?,' +
' "HISTORY.CREATEDAT" = now(),' +
' "HISTORY.CHANGEDAT" = now(),' +

239

SAP HANA Extended Application Services, Advanced model Development

' "CURRENCY" = ?');
pStmt.setString(1, PartnerId);
pStmt.setString(2, '01');
pStmt.setString(3, '0000000033');
pStmt.setString(4, '0000000033');
pStmt.setString(5, 'EUR');
pStmt.execute();
pStmt.close();

}
catch (e) {
return;
}
}

5) The next part is very similar
and handles the before
creation for the address
table.

function address_create_before_exit(param) {
var

after = param.afterTableName;

var pStmt;
try {
pStmt = param.connection.prepareStatement('select
"addressId".NEXTVAL from dummy');
var rs = pStmt.executeQuery();
var AddressId = '';
while (rs.next()) {
AddressId = rs.getString(1);
}
pStmt.close();
pStmt = param.connection.prepareStatement('update "' + after
+ '" set "ADDRESSID" = ?,' +
'ADDRESSTYPE = ?,' +
'"VALIDITY.STARTDATE" = TO_DATE(' + "'2000-0101', 'YYYY-MM-DD')," +
'"VALIDITY.ENDDATE" = TO_DATE(' + "'9999-1231', 'YYYY-MM-DD')" );
pStmt.setString(1, AddressId);
pStmt.setString(2, '02');
pStmt.execute();
pStmt.close();
}
catch (e) {
return;
}

240

SAP HANA Extended Application Services, Advanced model Development

}
6) The final part is different
because it handles the
association between two
entities. The input
parameters pass in the data
from both the principal and
dependent entities. We link
the two by updating the
business partner table with
the address id from the
address table. Notice at
this point we don’t have any
special processing for the
batch. We simply assume
that the records for both the
address and the business
partners will be passed in
with their correct generated
keys although the whole
operation is happening in
one transaction.

/**
@param {connection} Connection - The SQL connection used in the OData
request
@param {principalTableName} String - The name of a temporary table with the
entity type at the principal end of the association
@param {dependentTableName} String -The name of a temporary table with
the dependent entity type
*/

function assocation_create_exit(param){
var
princ = param.principalTableName;
var
dep = param.dependentTableName;

var
pStmt = param.connection.prepareStatement('select * from "' +
princ + '"');
var Principal =
SESSIONINFO.recordSetToJSON(pStmt.executeQuery(), 'Details');
pStmt.close();
var
pStmt = param.connection.prepareStatement('select * from "' +
dep + '"');
var Dependent =
SESSIONINFO.recordSetToJSON(pStmt.executeQuery(), 'Details');
pStmt.close();
$.trace.debug(JSON.stringify(Principal));
$.trace.debug(JSON.stringify(Dependent));
var pStmt = param.connection.prepareStatement('update
"MD.BusinessPartner" ' +
' SET "ADDRESSES.ADDRESSID" = ? WHERE
"PARTNERID" = ? ');
pStmt.setString(1, Dependent.Details[0].ADDRESSID);
pStmt.setString(2, Principal.Details[0].PARTNERID);
pStmt.execute();
pStmt.close();
}

7) Next we need to create the
user interface. Using what
you have learned create a
new SAPUI5 application
named odataDeep with a
similar structure to the
earlier applications you
created (index.html,
Component.js, view folder,

241

SAP HANA Extended Application Services, Advanced model Development

App.view.xml, and
App.controller.xml)
8) For the use of the $batch
with content-ids we can’t
use the SAPUI5 odata
object. We must build the
complete request object
ourselves. This also means
that we will be calling the
service with jQuery.ajax and
must handle the CSRF
token request ourselves.
For this we will refer to the
common/csrf.js we created
near the beginning of this
exercise.
If you need help writing this
code please refer to the
solution at:
https://github.com/SAP/com
.sap.openSAP.hana5.templ
ates/blob/master/ex4/ex4_3
1
9) In the view rendering we
want to simply have three
fields and a button. The
three fields are for
Company Name, City, and
Email Address.
If you need help writing this
code please refer to the
solution at:
https://github.com/SAP/com
.sap.openSAP.hana5.templ
ates/blob/master/ex4/ex4_3
2

242

<core:View
controllerName="sap.shineNext.odataDeep.view.App"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc"
xmlns:core="sap.ui.core" >
<Panel
headerText="New Business Partner Details"
expandable="true"
expanded="true">
<List width = "600px">
<InputListItem label="Company Name">
<Input id="cName" value="{/CompanyName}" />
</InputListItem>
<InputListItem label="City">
<Input id="city" value="{/City}" />
</InputListItem>
<InputListItem label="Email">
<Input id="email" value="{/Email}" />
</InputListItem>
</List>
<Button text="Create Record"
press="callCreateService" />
</Panel>
</core:View>

xhr. body +='\r\n'.hana5.model. body += 'Content-ID: 1\r\n'. // make everything inside this View appear in Compact mode }.controller("sap.getView().PARTNERID = "0000000000". The XSODATA framework on the server side will replace these values during processing.COMPANYNAME = result.ui. oAddress. '2.setRequestHeader("Content-Type".setRequestHeader("DataServiceVersion". This allows us to create a place holder to represent the keys of the object which won’t be generated until server side.getData().setRequestHeader("X-CSRF-Token". xhr.CompanyName.getView(). '/sap/hana/democontent/epm/services/businessPartnersAddresses. 'application/json').ui. xhr.setRequestHeader("Accept". var oBusinessPartner = {}. oAddress.view. true). '2. var body = ''.0'). token).setModel(model). var xhr = new XMLHttpRequest(). If you need help writing this code please refer to the solution at: https://github.City. body += 'Content-Transfer-Encoding:binary\r\n'.shineNext.EMAILADDRESS = result.open("POST". oBusinessPartner. xhr.uri = "$2". body +='\r\n'. this. oLink. this.sap. callCreateService: function(){ var result = this. var oAddress = {}.Email. Advanced model Development 10) For the controller we have one event handler for the press of the button. oBusinessPartner. We can then use $1 and $2 in the association URL and body as placeholders for the actual values. body +='Content-Type:multipart/mixed.templ ates/blob/master/ex4/ex4_3 3 //To use a javascript controller its name must end with .CITY = result. oBusinessPartner. xhr. here we must build the complete multiple part request.getModel().ADDRESSID = "0000000000".App".addStyleClass("sapUiSizeCompact").js sap. { onInit: function() { var model = new sap. var oLink = {}.setRequestHeader("MaxDataServiceVersion". Notice that in the individual request headers we use the Content-ID option.getView(). var token = getCSRFToken(). 'multipart/mixed.xsodata/$b atch'.odataDeep. Unlike the earlier exercise where the SAPUI5 framework did all the work.JSONModel({}).boundary=batch'). body += '--batch' + '\r\n'. body += 'POST BusinessPartners HTTP/1.openSAP.1\r\n'. body += 'Content-Type:application/http' + '\r\n'.com/SAP/com .controller.0'). body += '--changeset' + '\r\n'. However this event handler is very important because this is where we will build the complete OData $batch request.boundary=changeset' + '\r\n'.json. body +='Content-Transfer-Encoding:binary'+ '\r\n'.SAP HANA Extended Application Services. xhr. 243 .

body += "Content-Length:" + jsonLink.templ 244 jQuery. xhr. body +='\r\n'. body += 'POST Addresses HTTP/1.m. xhr.extend("sap. body +='\r\n'. jQuery. body += jsonLink + '\r\n'.stringify(oAddress). Advanced model Development body += "Content-Type: application/json\r\n". body += jsonBP + '\r\n'. .m. body += '--changeset' + '\r\n'.SAP HANA Extended Application Services. sap. body += '--changeset' + '\r\n'. body +='\r\n'. body += jsonAdd + '\r\n'.hana5.Component".MessageBox").MessageToast. body += 'PUT $1/$links/AddRef HTTP/1.shineNext.require("sap. body += 'Content-Transfer-Encoding:binary\r\n'. body += 'Content-ID: 2\r\n'. 11) Finally we need to create the Component.require("sap.sap.core. body += "Content-Length:" + jsonAdd. var jsonAdd = JSON. If you need help writing this code please refer to the solution at: https://github.1\r\n'.com/SAP/com .show("Business Partner created"). var jsonBP = JSON.sap.sap.stringify(oLink). body += "Content-Length:" + jsonBP.js file.length +'\r\n'.stringify(oBusinessPartner).UIComponent. } }). var jsonLink = JSON. body +='\r\n'.declare("sap. body +='\r\n'.MessageToast").1\r\n'. body += 'Content-Type:application/http' + '\r\n'. body += 'Content-Transfer-Encoding:binary\r\n'.odataDeep.m.length +'\r\n'. { init: function(){ jQuery. body += '--changeset' + '--\r\n'.shineNext. body += '--batch' + '--\r\n'.sap.ui.length +'\r\n'.send(body). body += 'Content-Type:application/http' + '\r\n'.odataDeep.openSAP. body += "Content-Type:application/json\r\n".onload = function() { }. body +='\r\n'. sap.Component"). body += "Content-Type:application/json\r\n".

ui. } }).view.App".odataDeep.core.SAP HANA Extended Application Services.view({ id: "app".prototype. type: "XML".shineNext. title: "OData Deep Insert Exercise".apply(this.init. 13) Test your application in a web browser using the Run option. createContent: function() { var settings = { ID: "odataDeep". var oView = sap. viewData: settings }). The URL would be /odataDeep/ 245 . return oView. }. Advanced model Development ates/blob/master/ex4/ex4_3 4 sap. viewName: "sap. description: "SHINE OData Deep Insert Exercise" }.ui. arguments). 12) Save your files and re-run the web module.UIComponent.

JS Objective In exercise 3 we created a Node. We will also see how to create language translatable text strings and HANA database queries from Node. We will see how these techniques are applied to common operations like HTTP web service calls or even SAP HANA database access. You will learn about how to create and use reusable code in the form of node.js.js modules. Our final part of this exercise will demonstrate the ease at which you can tap into the powerful web sockets capabilities of Node. You will use one of the most popular modules – express. You will learn about the fundamentals of the asynchronous nature of nodel. but didn’t really do much Node.json to define dependencies to these modules which make the installation of them quite easy. You will use packages.js module in the SAP Web IDE for SAP HANA.json  Local Modules  SAP HANA database access from node. We only were using Node. But we certainly aren’t limited to only the functionality provided by XSJS and XSODATA. We will so see how this asynchronous capability allows for non-blocking input and output.js.js to run XSJS and XSODATA services. It not only allows backward compatible support for much of your existing development. but it provides a simplified programming model as an alternative to the non-block I/O event driven programming model normally used by Node. The support for XSJS and XSODATA is an important feature for XS Advanced. In this exercise we will learn how to extend our existing Node.js specific programming.js.js  Basic asynchronous processing  Non-blocking I/O  Non-blocking HTTP requests  Non-blocking database requests  Text bundles  Web Sockets chat application 246 . This technique is one of the basic things that makes Node.js as well.js development different from other JavaScript development and also creates one of the reasons for its growing popularity. Advanced model Development EXERCISE 5 – NODE.js module. Any message sent from the SAPUI5 client side application will be propagated by the server to all listening clients. You will use express to handle multiple HTTP handlers in the same service by using routes.js. We will use web sockets to build a simple chat application. We have access to the full programming model of Node.SAP HANA Extended Application Services. Exercise Description  Modules  Express Module and package. which helps with the setup the handling of the request and response object.

//Initialize the XSJS Compatibility Layer init.listen(port.js itself as lean as possible.createServer().initXSJS(app). //Start the Server server. express is a module that wraps and extends the low level http library and provides many additional services. no-unused-vars: 0. Advanced model Development EXERCISE 5 – SOLUTION Exercise 5. Let’s separate out the logic for the Node. server.js startup and the XSJS bootstrap into separate functions and make our server. var port = process.address().env.info("HTTP Server: " + server. One is for the http built-in module and the other is the popular open source module – express.js logic to start up the XSJS compatibility and that’s it.SAP HANA Extended Application Services. var server = require("http").js source file. /*eslint no-console: 0. //Initialize Express App for XSA UAA and HDBEXT Middleware var app = init. global. function() { console. app).port).js code as well. At the same time we still want to support our existing XSJS and XSODATA services from this server.js module requirements toward the beginning of the file. We would like to extend server.1: Modules and Express Explanation Screenshot 1. Return to the core-js module and the server. Replace the current code in server.js with the following.PORT || 3000. We start with two new Node.on("request". server). var init = require(global. //Setup Routes var router = require(".js is acting as a web server and handling http requests/responses.__base = __dirname + "/". }). no-undef:0*/ "use strict".__base + "utils/initialize").js to also handle some purely Node.js. If you need help writing this 247 . 2. We currently have enough Node./router")(app. One of the most common tasks in Node.initExpress().

This is how reusable modules expose functions externally. In this folder create a file named initialize. Create a folder in core-js called utils. var appContext = logging.createAppContext(). For the initiExpress we want to intialize the use of Express and inject our UAA service and HANA service middleware into Express.exports.hana5.js Inside initialize.JWTStrategy(xsenv.templates/ blob/master/ex5/ex5_1 3. //Initialize Express App for XS UAA and HDBEXT Middleware var app = express(). This is similar to the options section of the server. module.js syntax. var xsHDBConn = require("sap-hdbext").js we will use the node.openSAP.use("JWT".SAP HANA Extended Application Services. new xssec. var xssec = require("sap-xssec").js file we used to set the configuration for the XSJS module. This will allow express to enforce our UAA requirements as well as create a HANA database client available to all express route requests. var passport = require("passport").s ap. passport. Advanced model Development code please refer to the solution at: https://github.com/SAP/com. //logging var logging = require("sap-logging").getServices({ uaa: { tag: "xsuaa" } . var express = require("express"). We want to create two functions – initExpress and initXSJS 4. We are doing essentially the same thing here – we are telling the service how to lookup the connection and security 248 initExpress: function() { var xsenv = require("sap-xsenv").

}).middleware()).openSAP.hana5.sap. Advanced model Development parameters.log("[WARN]".expressMiddleware(appContext)).authenticate("JWT". app. we still want to configure the xsjs module but no longer want it to listen directly on our service port.use(logging. For the initXSJS.js express middleware.openSAP. xsenv.extend({ // anonymous : true.tem plates/blob/master/ex5/ex5 _3 }.initialize()). return app. } // start server var xsjsApp = xsjs(options). initXSJS: function(app) { var xsjs = require("sap-xsjs").s ap. } // configure UAA try { options = xsjs. app.extend(options. { session: false }). If you need help writing this code please refer to the solution at: https://github.getServices({ hana: { tag: "hana" } })).SAP HANA Extended Application Services.log("[WARN]". 249 .env.message). xsHDBConn. var xsenv = require("sap-xsenv"). //configure HANA try { options = xsjs. answer: 42 } }). } catch (err) { console. context: { base: global. env: process. } catch (err) { console.use( passport.xsjs". err. If you need help writing this code please refer to the solution at: https://github. Instead we will start our own instance of express add the xsjs as a root route handler. var options = xsjs. The xsHDBConn is an instance of the sap-hdbext module designed to expose pooled database connections as a Node. err.extend(options.uaa)). xsenv. app.com/SAP/com.message).com/SAP/co m.templates/ blob/master/ex5/ex5_2 5.__base.use(passport.getServices({ uaa: { tag: "xsuaa" } })). // remove to authenticate calls redirectUrl: "/index.hana5.

250 . create a folder in core-js called router with an index. We want to create a good project structure that can acomidate many different Express route requests./routes/myNode.use(xsjsApp). Advanced model Development app.js with application specific logic. Rather than filling up our server. To follow some Express best practices. Modules don’t all have to come from central repositories. } 6. Notice that in the previous additions we added a reference to a module called .js. This is the root route handler we referenced back in step 2 in our server. They can also be a way of modularizing your own code (similar to XSJSLIB files).js. 7. The handler for this route will be called myNode.js module which will be local to our project. That is exactly what we will do here.SAP HANA Extended Application Services. This is a Node. For now only create a single route for the path /node.js in it.js module named myNode. we will break that out into its own Node.

function(req. //Hello Router app.js.get("/". return app. res) { res.s 251 . module. Notice express in this module has a root route handler.Router().exports = function() { var app = express.js. Add the following code to your myNode. Create a new folder called routes inside core-js/router. 10. But this will relatively to where it is attached in router/index.send("Hello World Node.Look at the package. no-shadow: 0. If you need help writing this code please refer to the solution at: https://github.js module to our project.SAP HANA Extended Application Services.js"). You will see the dependencies section which lists all required libraries and their versions. Advanced model Development 8.com/SAP/com. }). /*eslint no-console: 0. We manually added the express Node. }. var express = require("express"). 9.js file. Therefore this logic will still respond relative to the /node route handler base we specified earlier. While here we also need a few of the other modules we will need later in the exercise. so we also need to extend the dependencies section here. Then create a file called myNode. no-unused-vars: 0. This will add a simple GET handler that returns a “Hello World” message when requested.json file in the editor. newcap: 0*/ "use strict".

"authenticationMethod": "route".*)(. { "source": "(. "replace": { "pathSuffixes": ["index.templates/ blob/master/ex5/ex5_4 11. "authenticationType": "xsuaa". "routes": [{ "source": "/node(. "csrfProtection": true.html"].*)(.Our Node. "destination": "core-backend". "authenticationType": "xsuaa" }. "authenticationType": "xsuaa" }. "destination": "user-backend" }.SAP HANA Extended Application Services.html". { "source": "(. "authenticationType": "xsuaa" }.html". 12. "localDir": "resources".*)". "destination": "core-backend". "destination": "core-backend". { "source": "/user/(.json of our HTML5 module. { "source": "/(. 252 { "welcomeFile": "index.*)". "csrfProtection": true.js module is essentially finished.We can now run the core-js module.xsjs)". however before we can run it we also need to add a new route to the xs-app. "vars": ["ui5liburl"] } }] } .xsodata)".*)". Advanced model Development ap.hana5.openSAP. "odataTest.

It will need to rebuild and redeploy due to the added route.js module we just implemented in this exercise.xsjs in the browser. 16.In the running tab. Advanced model Development 13. you should see the index.Now change the path in the browser to /node/. We can add the url to our xsjs service /index. 15. 14. You should see Hello World Node.js this is being returned from the new route handler and Node.So now run the web module. This will test to make sure that our XSJS and XSODATA paths are still accessible even though we swapped out the root handler. 253 .html from earlier. You should see that the build and deploy was successful.SAP HANA Extended Application Services.

client. res) { var client = req. } }).prepare( "select SESSION_USER from \"DUMMY\" ".type("application/json"). } statement. return.type("text/plain"). }). return.send("ERROR: " + err. Then create a prepared statement for the SELECT of SESSION_USER from dummy (using the synonym we created in Exercise 2).send("ERROR: " + err.com/SAP/com.get("/example1".openSAP.db). Note: if you don’t want to type this code. res. Let’s extend the logic here with a URL handler for /node/example1 which will issue a database SELECT statement against the DUMMY table and return the current database user. function(err.stringify({ Objects: results }). function(err. statement) { if (err) { res.status(200).type("text/plain").SAP HANA Extended Application Services.hana5.In-line Callbacks app.status(500).toString()).db.exec([].status(500). function(req. } else { var result = JSON. we recommend that you cut and paste it from this web address https://github. In this exercise we will look at how to use the HANA database access library to send queries to the database.templates/ blob/master/ex5/ex5_5 254 //Simple Database Select . Advanced model Development Exercise 5. results) { if (err) { res. Return to the core-js module and the myNode.s ap.2: HANA Database Access from Node. Execute the statement and send the results as JSON in the response object. 2. Now add a new route for /example1 that gets the database connection/client from the express request object (req. }).js source file.toString()).send(result).js Explanation Screenshot 1. .

4. You should see the output of your successful SELECT statement. Advanced model Development 3. Since its already running and we didn’t make any changes to it.waterfall([ function prepare(callback) { client. function(err. statement) { 255 .get("/example2". res) { var client = req. You might have noticed that the default Node.db. 7. prepared statement.js programming approach is to use callbacks/event handlers for each operation. You should see that the build and deploy was successful. 6. We can now run the core-js module. 5. async. //Simple Database Select . execution. function(req.SAP HANA Extended Application Services. Click on the web folder and the run window should change to the details of the running HTML5 module. etc) are all non-blocking var async = require("async"). This is because even the different parts of a database request (connection.Async Waterfall app. Now change the path in the browser to /node/example1. you can just click on the Application link in the bottom left corner of the window to reopen it in your web browser.prepare("select SESSION_USER from \"DUMMY\" ".

callback) { This module doesn’t really change the runtime aspects of the code.send(result). }).openSAP. statement.send("ERROR: " + err.status(500). return. results. callback(null. }. }). function execute(err. results) { callback(null. callback) { statement.stringify({ Objects: results }). statement).SAP HANA Extended Application Services.type("application/json").js and add a second route handler. we recommend that you cut and paste it from this web address https://github. function(execErr. execErr. Advanced model Development operations. While this provides considerable parallelization and performance opportunities. but organizes the callback functions in an easier to read array instead of in-lining them within each other. As a bonus part of this exercise you can return to myNode.toString()). res. } else { var result = JSON.exec([]. . }).status(200).sap. function response(err. }. results). Note: if you don’t want to type this code. err. } callback(). /example2 that performs the same select but uses the async module. it can also make the code more difficult to read.type("text/plain").com/SAP/co m.tem plates/blob/master/ex5/ex5 _6 Then run the core-js module and test again at /node/example2 256 if (err) { res.hana5. } ]).

Add a second module require statement for . var asyncLib = require(global.server) { app. Advanced model Development Exercise 5. 257 . no-unused-vars: 0. Add the following code to your exerciseAsync. var express = require("express"). Instead this is really just a test framework.js").js development different from other JavaScript development and also creates one of the reasons for its growing popularity. but isn’t what we want you to focus on for this exercise.__base + "async/databaseAsync. require(". module. We will see how these techniques are applied to common operations like HTTP web service calls or even SAP HANA database access. app. require(".__base + "async/async. 3.SAP HANA Extended Application Services. module.exports = function(server) { var app = express.js /*eslint no-console: 0. var dbAsync2 = require(global. Return to the core-js module and the router/index. var WebSocketServer = require("ws").Server. You can look at this code if you want. Create a new file in your router/routes folder called exerciseAsync./routes/myNode")()).js file. We will also see how this asynchronous capability allows for non-blocking input and output.js.js").3: Asynchronous Non-Blocking I/O In this exercise. This technique is one of the basic things that makes Node.exports = function(app.use("/node"./exerciseAsync Screenshot "use strict".js modules – each focusing on a different Node.js"). var dbAsync = require(global. new-cap:0 */ "use strict".Router().js.js source file. you will learn about the fundaments of the asynchronous nature of Node. 2. }. We will instead write the important parts of this exercise in a series of additional Node.__base + "async/databaseAsync2. Explanation 1./routes/exerciseAsync")(server)).use("/node/excAsync".

log("received: %s". function(ws) { console.send(message).com/SAP/com.status(200).__base + "async/fileSync.templates/b lob/master/ex5/ex5_7 var fileSync = require(global. wss.sa p.js").clients[i]. break. res. function(message) { console.parse(message).send(output).on("message". var data = JSON.dbCall(wss). var wss = new WebSocketServer({ server: server.SAP HANA Extended Application Services. break. case "fileSync": fileSync. var httpClient = require(global.on("connection".js"). message). message).__base + "async/httpClient. console.type("text/html").js"). app. break.hana5. Advanced model Development asynchronous aspect. }.use(function(req.action) { case "async": asyncLib. we recommend that you cut and paste it from this web address https://github. wss.callService(wss). }).broadcast = function(data) { var message = JSON.Test Framework for Async Examples</br>".log("Connected"). break. 258 . switch (data.clients) this. var fileAsync = require(global. Note: if you don’t want to type this code. case "httpClient": httpClient.log("sent: %s".stringify({ text: data }).fileDemo(wss).fileDemo(wss). ws. res) { var output = "<H1>Asynchronous Examples</H1></br>" + "<a href=\"/exerciseAsync\">/exerciseAsync</a> . path: "/node/excAsync" }). case "fileAsync": fileAsync.__base + "async/fileAsync.openSAP. for (var i in this. case "dbAsync": dbAsync.asyncDemo(wss).

break.openSAP.dbCall(wss).broadcast("Error: Undefined Action: " + data.s ap.zip in the Downloads folder. Press browse and file the file exerciseAsync. 5.templates/ raw/master/ex5/exerciseAsync . break. Keep all other selections at their defaults and press OK. Advanced model Development break. default: wss. return app.action). We will also need a test user interface for this exercise. }.com/SAP/com.zip Go to the web/resources folder and right mouse click. 259 . Download the content from this address: https://github.send(JSON.stringify({ text: "Connected to Exercise 3" })).hana5. ws. 4. case "dbAsync2": dbAsync2.SAP HANA Extended Application Services. }). } }). Choose Import->From File System.

9.zip from the Download folder on your local machine. In the web module. 8. Create a folder under core-js called async.s ap. 7.hana5. This should import the complete UI for you.SAP HANA Extended Application Services. also edit the xs-app. Right mouse click on /corejs/async and choose Import -> From File System. This is where we will create the rest of the files in this exercise part.templates/ raw/master/ex5/async. Add the Websockets enabled section after the authenticationMethod. Keep all other settings the same and press OK. The rest of the files can be downloaded from the following address: https://github.json.openSAP.zip Create folder in the core-js folder called async. Advanced model Development 6. 260 "websockets": { "enabled": true }.com/SAP/com. Choose the file async. .

11. 13.So now run the web module since we have new frontend content as well. you should see the index.In the running tab.SAP HANA Extended Application Services.We can now run the core-js module. 12. Advanced model Development 10.html from earlier. 261 . You should see that the build and deploy was successful.

SAP HANA Extended Application Services.js is asynchronous nonblocking execution of many core elements.What do you expect this code will output? From many other programming languages we would expect sequential processing and therefore the End output wouldn’t come until after the timer expired. 16. When asynchronous processing is applied to these operations.js code. Finally we will issue an ending message. You should see the test framework for this exercise. 15.Now change the path in the browser to /exerciseAsync. we can keep from 262 . However this asynchronous nature of node.Perhaps a timer seemed like an obvious asynchronous operation. In test UI. However part of the power of node. 17. Advanced model Development 14. then set a timer which will issue a message after 3 seconds.Basic Async runs the async. In this code we will output a start message.js is often used when programs must wait on input or output. press the Basic Async button.

everything is output in exactly the same order as the lines of code were listed in the application because all operations were synchronous. 19. Program execution didn’t continue until each read operation had completely finished. 263 . As you might expect. 18.Test your fileSync. Let’s first look at the difference between synchronous and asynchronous file operations.The fileSync.SAP HANA Extended Application Services.js from the UI test tool.js is using the fs library and the function readFileSync to read each of the two text files. Advanced model Development blocking execution of other logic while we wait on things like file access. http requests or even database query execution. After each read operation output there is a message.

It doesn’t get executed until the read operation is complete. This will call the US Library of Congress Image Search (a REST API which requires no authentication or API Key to keep the exercise simple). but the rest of the program flow continues and isn’t blocked by the file operation. In this exercise let’s see how node. Use the get function of the http library to call to http://www. it’s possible that the second might have finished and output first.js also makes calling external HTTP services non-blocking. HTTP requests are another area where our programs must often wait on an external response.Now run fileAsync. Issue a message before and after the HTTP request.SAP HANA Extended Application Services.js from the test UI. 21.js.gov/pictures/se arch/?fo=json&q=SAP. 264 . Notice that the message output now is embedded as an in-line callback function.Now to look at fileAsync. The http library we used in earlier exercises can also be used to make HTTP requests. Also if the first file had been significantly larger than the second. The output of this exercise gives us very different results.Similar to file operations. This has powerful implications to how we code applications.loc. Both after comments are output before either of the file contents. . Advanced model Development 20. 22.

For this exercise we’ve already coded the database requests in a reusable module for you. Advanced model Development 23. 24. 265 . then issues another message. First we have databaseAsync.js from the test UI. Earlier in this exercise. This Issues a message. This allows us to issue multiple requests to the underlying HANA database in parallel and without stopping the processing flow of the JavaScript application logic. then calls two functions (callHANA1 and callHANA2).js.Perhaps most interesting to us is that this non-blocking concept can also be extended to database access. Similar to the earlier file exercise.Test your httpClient. so you can concentrate on the asynchronous flow. This will execute two different queries in the HANA database. you learned about making database access to HANA.SAP HANA Extended Application Services. the after http call console message is output before the response from the HTTP request.

This allows some of the commands to execute in parallel as before.js we adjust the logic to use the async.Test your databaseAsync. Advanced model Development 25.js from test UI. we can output this final message after both queries are complete. Because we have a sync point after all parallel execution is complete. Maybe you want several database operations to happen in parallel. There is also no guarantee that query 1 will finish before query 2. the messages you issued after the database requests are actually output first. 27. In databaseAsync2. Only then are the database query results returned.parallel function. 26. but then some logic to execute only after all queries are complete.Test your databaseAsync2.But what if you want more control over the flow of program execution.js can make easier. As you are hopefully learning to expect. 266 . The execution is similar to before. but now we have the final message after all queries are complete.SAP HANA Extended Application Services. but then have a sync point once all operations are complete to allow further processing. This is one of things the async library in node.js from the test UI. We will output one final message after everything is done.

SAP HANA Extended Application Services. Advanced model Development 267 .

module.use("/node".js "use strict". 4. app. Add a route for a new module named textBundle that corresponds to /node/textBundle in the router/index. When creating a new TextBundle instance the input are path (value messages to point to your message. function getLocale(req) { var lang = req. Advanced model Development Exercise 5.SAP HANA Extended Application Services.js.server) { app. Add the following code to your textBundle.length < 1) { return.use("/node/excAsync". var langparser = require("accept-language-parser").exports = function(app. It has implemented an HTTP handler for the root URL using express./routes/exerciseAsync")(server)). Return to the core-js module.properties file) and locale which should call getLocale passing in the req object./routes/myNode")()).use("/node/textBundle".headers["accept-language"].4: Text Bundles Explanation Screenshot 1. if (!lang) { return.TextBundle.js file. require(". var app = express. var TextBundle = require("sap-textbundle"). } . var express = require("express").Router(). Create a new file in your router/routes folder called textBundle. } var arr = langparser. In the processing of this handler use the TextBundle library. require(". 3. require(". app.parse(lang). }./routes/textBundle")()). var os = require("os"). if (!arr || arr. Then write into the res object with the 268 "use strict". 2.

getText("greeting". "utf-8"). Choose the file i18n.end(greeting.code. we recommend that you cut and paste it from this web address https://github.zip Right mouse click on the corejs folder and choose Import-> From File System. 5.sap. function(req. return app.tem plates/blob/master/ex5/ex5 _8 var locale = arr[0].get("/". } return locale. Keep all other settings at their default values.SAP HANA Extended Application Services.templates/ raw/master/ex5/i18n. res) { var bundle = new TextBundle(global. os.zip from your Download local folder. 6. [os.openSAP. res.region) { locale += "_" + arr[0].region. var greeting = bundle.hana5.writeHead(200.com/SAP/co m. if (arr[0]. res.type()]).__base + "i18n/messages". Advanced model Development TextBundle getText function (passing in the text ID of greeting and two parameters of os.hostname() and os. Choose OK. { "Content-Type": "text/plain. We can now run the core-js module. Note: if you don’t want to type this code. getLocale(req)). charset=utf-8" }). }). You can download these files from here: https://github.type().hostname().s ap. }.openSAP.exports = function() { app.com/SAP/com. 269 . We need a few text files to test with. } module.hana5.

html from earlier. You should see that the build and deploy was successful. 10. 9.Now change the path in the browser to /node/textBundle. you should see the index. Advanced model Development 7. You should see the English message output from your text file in the i18n folder. 8. 270 . In the running tab. So now run the web module.SAP HANA Extended Application Services.

go into the browser Settings.SAP HANA Extended Application Services. Advanced model Development 11. 271 .In order to test the translated strings. Search for Lang and then choose the Language and input settings button.

Drag and drop to raise German to the top of the list 13.Please return the browser settings to English at the top.Add German and Japanese to the language list.Repeat the process raising Japanese [ja] to the top of the list and refresh the web page 15. 14.Refresh the web browser and you should now see the German text. 272 .SAP HANA Extended Application Services. Advanced model Development 12.

/routes/exerciseAsync")(server)).js and pass the server variable in as well.js.js module.use("/node/chat". app.exports = function(app. Return to the core./routes/chatServer")(server)). }. app. 2.5: Web Sockets Our final exercise part in this section will demonstrate the ease at which you can tap into the powerful web sockets capabilities of node.use("/node/excAsync". Explanation Screenshot 1.exports = function(server) { var app = express. Add an express route handler for this chatServer module in the router/index.use("/node". 3. var express = require("express").use("/node/textBundle". Add the following code to your chatServer.js file. module. Create a new file in your corejs/router/routes folder called chatServer. "use strict". Advanced model Development Exercise 5. Any message sent from the SAPUI5 client side application will be propagated by the server to all listening clients. require(". app. module. require(". The Node. var WebSocketServer = require("ws").js. require(".SAP HANA Extended Application Services. 273 . We will use web sockets to build a simple chat application.js module for Web Sockets which we are going to use is ws./routes/textBundle")()).Server.Router(). require(".server) { app./routes/myNode")()). 4. "use strict".

function(ws) { ws.js Web Socket Examples</H1></br>" + "<a href=\"/exerciseChat\">/exerciseChat</a> . function(message) { console. text: "Hello from Node. we recommend that you cut and paste it from this web address https://github.on("connection".log("received: %s".send(output). console.type("text/html").openSAP.broadcast(message). Advanced model Development Require it and create a new instance of the WebSocketServer. ws. 274 .clients[i].clients) this.status(200). wss. We will also need a nice user interface for this exercise. var wss = new WebSocketServer({ server: server. Choose Import->From File System. zip Go to the web/resources folder and right mouse click. }).js XS Server" })).send(JSON.Chat Application for Web Socket Example</br>".hana5.on("message". }. res) { var output = "<H1>Node. 5. This is then a recommended implementation for the remainder of the Web Sockets functionality to both receive and send messages.use(function(req. }.broadcast = function(data) { for (var i in this. path: "/node/chatServer" }).com/SAP/c om. message).templates/ raw/master/ex5/exerciseChat. Download the files for the UI from here: https://github. wss. }). Note: if you don’t want to type this code. res.SAP HANA Extended Application Services. data).com/SAP/com.send(data).hana5. app.openSAP.sap.t emplates/blob/master/ex 5/ex5_9 wss. }). return app.s ap.log("sent: %s".stringify({ user: "XS".

275 . Advanced model Development 6. This should import the complete UI for you.SAP HANA Extended Application Services. You should see that the build and deploy was successful. Press browse and file the file exerciseChat.zip in the Downloads folder. Keep all other selections at their defaults and press OK. 9. 8. We can now run the core-js module. 7.

276 . 11. 12.html from earlier.In the running tab. you should see the index.SAP HANA Extended Application Services.Open a second browser window and cut and paste the chat application URL into it.Now change the path in the browser to /exerciseChat. 13.So now run the web module. You should see the simple chat user interface. Advanced model Development 10.

SAP HANA Extended Application Services.Anything you type into either window is sent to the server and then pushed out to all listeners. If you want to test further open more than two browser windows. 277 . Advanced model Development 14.

SAP HANA Extended Application Services. Advanced model Development EXERCISE 6 – PACKAGING FOR TRANSPORT Objective Now that we have a completed application we can package it for transport Exercise Description  Build all modules  Build project to create MTAR  Download MTAR 278 .

The build and run process creates services on the XSA server.1: Package for Transport Explanation Screenshot 1. 279 . We now want to package our complete application so that it’s installable in its final form and ready to transport to downstream systems. Advanced model Development EXERCISE 6 – SOLUTION Exercise 6. but they should be considered “local” testing services only. 2. They are prefixed with your user name and workspace.SAP HANA Extended Application Services. Perform a build at the project level.

This is where the built archives for all our projects go. 280 . You can now manually download the MTAR file and install it from the command line using the XS DEPLOY command.SAP HANA Extended Application Services. After a few minutes. 4. you should now have a separate mta_archives project in your workspace. Advanced model Development 3.

SAP HANA Extended Application Services. The Code is only intended to better explain and visualize the syntax and phrasing rules for certain SAP coding. 281 . Advanced model Development Coding Samples Any software coding or code lines/strings (“Code”) provided in this documentation are only examples and are not intended for use in a production system environment. SAP does not warrant the correctness or completeness of the Code provided herein and SAP shall not be liable for errors or damages cause by use of the Code. except where such damages were caused by SAP with intent or with gross negligence.

All rights reserved. In particular. promise. The only warranties for SAP SE or SAP affiliate company products and services are those that are set forth in the express warranty statements accompanying such products and services. Nothing herein should be construed as constituting an additional warranty. 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. and they should not be relied upon in making purchasing decisions. or legal obligation to deliver any material. All forward-looking statements are subject to various risks and uncertainties that could cause actual results to differ materially from expectations. . or any related presentation. Some software products marketed by SAP SE and its distributors contain proprietary software components of other software vendors.sap. without representation or warranty of any kind. This document. code. if any. Please see http://www.com/corporateen/legal/copyright/index. National product specifications may vary.sap. and/or platform directions and functionality are all subject to change and may be changed by SAP SE or its affiliated companies at any time for any reason without notice.www.com © 2016 SAP SE or an SAP affiliate company. and SAP SE’s or its affiliated companies’ strategy and possible future developments. which speak only as of their dates. The information in this document is not a commitment. or to develop or release any functionality mentioned therein. SAP SE or its affiliated companies have no obligation to pursue any course of business outlined in this document or any related presentation. products. Readers are cautioned not to place undue reliance on these forward-looking statements. 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. and SAP SE or its affiliated companies shall not be liable for errors or omissions with respect to the materials. These materials are provided by SAP SE or an SAP affiliate company for informational purposes only. or functionality.epx#trademark for additional trademark information and notices.