-uuid
93 | %msg = new_message( id = 'ZCM_RAP_GENERATOR'
94 | number = '016'
95 | v1 = error_message
96 | "v2 = messages[ 1 ]-msgv2
97 | "v3 = messages[ 1 ]-msgv3
98 | "v4 = messages[ 1 ]-msgv4
99 | severity = CONV #( 'E' ) )
100 | %element-price = if_abap_behv=>mk-on
101 |
102 |
103 | ) TO reported_inventory_soap.
104 | "inventory entries where no price could be retrieved must not be passed to the MODIFY statement
105 | DELETE inventories INDEX sy-tabix.
106 | ENDTRY.
107 |
108 | ENDLOOP.
109 |
110 | "update involved instances
111 | MODIFY ENTITIES OF zi_rap_inventory_#### IN LOCAL MODE
112 | ENTITY Inventory
113 | UPDATE FIELDS ( Price CurrencyCode )
114 | WITH VALUE #( FOR inventory IN inventories (
115 | %tky = inventory-%tky
116 | Price = inventory-Price
117 | CurrencyCode = inventory-CurrencyCode
118 | ) )
119 | REPORTED DATA(reported_entities).
120 |
121 | "fill reported
122 | reported = CORRESPONDING #( DEEP reported_entities ).
123 |
124 | "add reported from SOAP call
125 | LOOP AT reported_inventory_soap INTO DATA(reported_inventory).
126 | APPEND reported_inventory TO reported-inventory.
127 | ENDLOOP.
128 |
129 |
130 | ENDMETHOD.
131 |
132 | ENDCLASS.
--------------------------------------------------------------------------------
/exercises/ex2/sources/zcl_ce_rap_products_####:
--------------------------------------------------------------------------------
1 | CLASS zcl_ce_rap_products_#### DEFINITION
2 | PUBLIC
3 | FINAL
4 | CREATE PUBLIC .
5 |
6 | PUBLIC SECTION.
7 |
8 | INTERFACES if_oo_adt_classrun .
9 | INTERFACES if_rap_query_provider.
10 |
11 | TYPES t_product_range TYPE RANGE OF zrap_####_sepmra_i_product_e-product.
12 | TYPES t_business_data TYPE TABLE OF zrap_####_sepmra_i_product_e.
13 |
14 | METHODS get_products
15 | IMPORTING
16 | it_filter_cond TYPE if_rap_query_filter=>tt_name_range_pairs OPTIONAL
17 | top TYPE i OPTIONAL
18 | skip TYPE i OPTIONAL
19 | EXPORTING
20 | et_business_data TYPE t_business_data
21 | RAISING
22 | /iwbep/cx_cp_remote
23 | /iwbep/cx_gateway
24 | cx_web_http_client_error
25 | cx_http_dest_provider_error
26 | .
27 |
28 | PROTECTED SECTION.
29 | PRIVATE SECTION.
30 | ENDCLASS.
31 |
32 |
33 |
34 | CLASS zcl_ce_rap_products_#### IMPLEMENTATION.
35 |
36 | METHOD if_oo_adt_classrun~main.
37 |
38 | DATA business_data TYPE TABLE OF zrap_####_sepmra_i_product_e.
39 | DATA filter_conditions TYPE if_rap_query_filter=>tt_name_range_pairs .
40 | DATA ranges_table TYPE if_rap_query_filter=>tt_range_option .
41 | ranges_table = VALUE #( ( sign = 'I' option = 'GE' low = 'HT-1200' ) ).
42 | filter_conditions = VALUE #( ( name = 'PRODUCT' range = ranges_table ) ).
43 |
44 | TRY.
45 | get_products(
46 | EXPORTING
47 | it_filter_cond = filter_conditions
48 | top = 3
49 | skip = 1
50 | IMPORTING
51 | et_business_data = business_data
52 | ) .
53 | out->write( business_data ).
54 | CATCH cx_root INTO DATA(exception).
55 | out->write( cl_message_helper=>get_latest_t100_exception( exception )->if_message~get_longtext( ) ).
56 | ENDTRY.
57 |
58 | ENDMETHOD.
59 |
60 | METHOD get_products.
61 |
62 | DATA: filter_factory TYPE REF TO /iwbep/if_cp_filter_factory,
63 | filter_node TYPE REF TO /iwbep/if_cp_filter_node,
64 | root_filter_node TYPE REF TO /iwbep/if_cp_filter_node.
65 |
66 | DATA: http_client TYPE REF TO if_web_http_client,
67 | odata_client_proxy TYPE REF TO /iwbep/if_cp_client_proxy,
68 | read_list_request TYPE REF TO /iwbep/if_cp_request_read_list,
69 | read_list_response TYPE REF TO /iwbep/if_cp_response_read_lst.
70 |
71 | DATA(http_destination) = cl_http_destination_provider=>create_by_url( i_url = 'https://sapes5.sapdevcenter.com' ).
72 | http_client = cl_web_http_client_manager=>create_by_http_destination( i_destination = http_destination ).
73 |
74 | odata_client_proxy = cl_web_odata_client_factory=>create_v2_remote_proxy(
75 | EXPORTING
76 | iv_service_definition_name = 'ZSC_RAP_PRODUCTS_####'
77 | io_http_client = http_client
78 | iv_relative_service_root = '/sap/opu/odata/sap/ZPDCDS_SRV/' ).
79 |
80 | " Navigate to the resource and create a request for the read operation
81 | read_list_request = odata_client_proxy->create_resource_for_entity_set( 'SEPMRA_I_PRODUCT_E' )->create_request_for_read( ).
82 |
83 | " Create the filter tree
84 | filter_factory = read_list_request->create_filter_factory( ).
85 | LOOP AT it_filter_cond INTO DATA(filter_condition).
86 | filter_node = filter_factory->create_by_range( iv_property_path = filter_condition-name
87 | it_range = filter_condition-range ).
88 | IF root_filter_node IS INITIAL.
89 | root_filter_node = filter_node.
90 | ELSE.
91 | root_filter_node = root_filter_node->and( filter_node ).
92 | ENDIF.
93 | ENDLOOP.
94 |
95 | IF root_filter_node IS NOT INITIAL.
96 | read_list_request->set_filter( root_filter_node ).
97 | ENDIF.
98 |
99 | IF top > 0 .
100 | read_list_request->set_top( top ).
101 | ENDIF.
102 |
103 | read_list_request->set_skip( skip ).
104 |
105 | " Execute the request and retrieve the business data
106 | read_list_response = read_list_request->execute( ).
107 | read_list_response->get_business_data( IMPORTING et_business_data = et_business_data ).
108 |
109 | ENDMETHOD.
110 |
111 |
112 | METHOD if_rap_query_provider~select.
113 | DATA business_data TYPE TABLE OF zrap_####_sepmra_i_product_e.
114 | DATA(top) = io_request->get_paging( )->get_page_size( ).
115 | DATA(skip) = io_request->get_paging( )->get_offset( ).
116 | DATA(requested_fields) = io_request->get_requested_elements( ).
117 | DATA(sort_order) = io_request->get_sort_elements( ).
118 |
119 | TRY.
120 | DATA(filter_condition) = io_request->get_filter( )->get_as_ranges( ).
121 |
122 | get_products(
123 | EXPORTING
124 | it_filter_cond = filter_condition
125 | top = CONV i( top )
126 | skip = CONV i( skip )
127 | IMPORTING
128 | et_business_data = business_data
129 | ) .
130 |
131 | io_response->set_total_number_of_records( lines( business_data ) ).
132 | io_response->set_data( business_data ).
133 |
134 | CATCH cx_root INTO DATA(exception).
135 | DATA(exception_message) = cl_message_helper=>get_latest_t100_exception( exception )->if_message~get_longtext( ).
136 | ENDTRY.
137 | ENDMETHOD.
138 |
139 | ENDCLASS.
140 |
--------------------------------------------------------------------------------
/exercises/ex2/sources/ex2_CLAS_zcl_ce_rap_products_####_final.txt:
--------------------------------------------------------------------------------
1 | CLASS zcl_ce_rap_products_#### DEFINITION
2 | PUBLIC
3 | FINAL
4 | CREATE PUBLIC .
5 |
6 | PUBLIC SECTION.
7 |
8 | INTERFACES if_oo_adt_classrun .
9 | INTERFACES if_rap_query_provider.
10 |
11 | TYPES t_product_range TYPE RANGE OF zrap_####_sepmra_i_product_e-product.
12 | TYPES t_business_data TYPE TABLE OF zrap_####_sepmra_i_product_e.
13 |
14 | METHODS get_products
15 | IMPORTING
16 | it_filter_cond TYPE if_rap_query_filter=>tt_name_range_pairs OPTIONAL
17 | top TYPE i OPTIONAL
18 | skip TYPE i OPTIONAL
19 | EXPORTING
20 | et_business_data TYPE t_business_data
21 | RAISING
22 | /iwbep/cx_cp_remote
23 | /iwbep/cx_gateway
24 | cx_web_http_client_error
25 | cx_http_dest_provider_error
26 | .
27 |
28 | PROTECTED SECTION.
29 | PRIVATE SECTION.
30 | ENDCLASS.
31 |
32 |
33 |
34 | CLASS zcl_ce_rap_products_#### IMPLEMENTATION.
35 |
36 | METHOD if_oo_adt_classrun~main.
37 |
38 | DATA business_data TYPE TABLE OF zrap_####_sepmra_i_product_e.
39 | DATA filter_conditions TYPE if_rap_query_filter=>tt_name_range_pairs .
40 | DATA ranges_table TYPE if_rap_query_filter=>tt_range_option .
41 | ranges_table = VALUE #( ( sign = 'I' option = 'GE' low = 'HT-1200' ) ).
42 | filter_conditions = VALUE #( ( name = 'PRODUCT' range = ranges_table ) ).
43 |
44 | TRY.
45 | get_products(
46 | EXPORTING
47 | it_filter_cond = filter_conditions
48 | top = 3
49 | skip = 1
50 | IMPORTING
51 | et_business_data = business_data
52 | ) .
53 | out->write( business_data ).
54 | CATCH cx_root INTO DATA(exception).
55 | out->write( cl_message_helper=>get_latest_t100_exception( exception )->if_message~get_longtext( ) ).
56 | ENDTRY.
57 |
58 | ENDMETHOD.
59 |
60 | METHOD get_products.
61 |
62 | DATA: filter_factory TYPE REF TO /iwbep/if_cp_filter_factory,
63 | filter_node TYPE REF TO /iwbep/if_cp_filter_node,
64 | root_filter_node TYPE REF TO /iwbep/if_cp_filter_node.
65 |
66 | DATA: http_client TYPE REF TO if_web_http_client,
67 | odata_client_proxy TYPE REF TO /iwbep/if_cp_client_proxy,
68 | read_list_request TYPE REF TO /iwbep/if_cp_request_read_list,
69 | read_list_response TYPE REF TO /iwbep/if_cp_response_read_lst.
70 |
71 | DATA(http_destination) = cl_http_destination_provider=>create_by_url( i_url = 'https://sapes5.sapdevcenter.com' ).
72 | http_client = cl_web_http_client_manager=>create_by_http_destination( i_destination = http_destination ).
73 |
74 | odata_client_proxy = cl_web_odata_client_factory=>create_v2_remote_proxy(
75 | EXPORTING
76 | iv_service_definition_name = 'ZSC_RAP_PRODUCTS_####'
77 | io_http_client = http_client
78 | iv_relative_service_root = '/sap/opu/odata/sap/ZPDCDS_SRV/' ).
79 |
80 | " Navigate to the resource and create a request for the read operation
81 | read_list_request = odata_client_proxy->create_resource_for_entity_set( 'SEPMRA_I_PRODUCT_E' )->create_request_for_read( ).
82 |
83 | " Create the filter tree
84 | filter_factory = read_list_request->create_filter_factory( ).
85 | LOOP AT it_filter_cond INTO DATA(filter_condition).
86 | filter_node = filter_factory->create_by_range( iv_property_path = filter_condition-name
87 | it_range = filter_condition-range ).
88 | IF root_filter_node IS INITIAL.
89 | root_filter_node = filter_node.
90 | ELSE.
91 | root_filter_node = root_filter_node->and( filter_node ).
92 | ENDIF.
93 | ENDLOOP.
94 |
95 | IF root_filter_node IS NOT INITIAL.
96 | read_list_request->set_filter( root_filter_node ).
97 | ENDIF.
98 |
99 | IF top > 0 .
100 | read_list_request->set_top( top ).
101 | ENDIF.
102 |
103 | read_list_request->set_skip( skip ).
104 |
105 | " Execute the request and retrieve the business data
106 | read_list_response = read_list_request->execute( ).
107 | read_list_response->get_business_data( IMPORTING et_business_data = et_business_data ).
108 |
109 | ENDMETHOD.
110 |
111 |
112 | METHOD if_rap_query_provider~select.
113 | DATA business_data TYPE TABLE OF zrap_####_sepmra_i_product_e.
114 | DATA(top) = io_request->get_paging( )->get_page_size( ).
115 | DATA(skip) = io_request->get_paging( )->get_offset( ).
116 | DATA(requested_fields) = io_request->get_requested_elements( ).
117 | DATA(sort_order) = io_request->get_sort_elements( ).
118 |
119 | TRY.
120 | DATA(filter_condition) = io_request->get_filter( )->get_as_ranges( ).
121 |
122 | get_products(
123 | EXPORTING
124 | it_filter_cond = filter_condition
125 | top = CONV i( top )
126 | skip = CONV i( skip )
127 | IMPORTING
128 | et_business_data = business_data
129 | ) .
130 |
131 | io_response->set_total_number_of_records( lines( business_data ) ).
132 | io_response->set_data( business_data ).
133 |
134 | CATCH cx_root INTO DATA(exception).
135 | DATA(exception_message) = cl_message_helper=>get_latest_t100_exception( exception )->if_message~get_longtext( ).
136 | ENDTRY.
137 | ENDMETHOD.
138 |
139 | ENDCLASS.
140 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DEV268 - SAP BTP ABAP Environment Connectivity and Integration
2 |
3 | [](https://api.reuse.software/info/github.com/SAP-samples/teched2020-DEV268)
4 |
5 | ## Description
6 |
7 | This repository contains the material for the SAP TechEd 2020 session called *DEV268 - SAP Cloud Platform, ABAP Environment Connectivity and Integration.*
8 |
9 | ## Disclaimer
10 |
11 | > Note that this workshop was first offered in 2020; consequently, all its assets were created before the branding changes related to SAP technology were announced in January 2021. For example, SAP Cloud Platform, ABAP environment has been renamed to SAP Business Technology Platform (BTP), ABAP environment.
12 |
13 | ## Overview
14 |
15 | In this session we will show you how you can use SAP Cloud Platform, ABAP environment for side-by-side extension scenarios with SAP S/4 HANA using the ABAP RESTful Application Programming Model
16 |
17 | 
18 |
19 | Our scenario is an inventory application that runs on SAP Cloud Platform, ABAP environment. This application will use product master data from an on premise S/4 HANA system that will be retrieved via calling an OData service and via calling a SOAP web service.
20 |
21 | To speed up the development we will use a tool called the RAP Generator that generates the complete stack of a RAP business object based on one or more tables that have to be created beforehand.
22 |
23 | For this workshop we even prepared a class that also creates the table for the inventory data and then calls the RAP Generator to generate the RAP business object on top. This allows us to skip writing lots of boiler plate coding that you otherwise would have to write yourself.
24 |
25 | And we can start much faster with the implementation of our side-by-side integration scenario, so that it fits into the schedule of a 2-hour hands-on session.
26 |
27 | ## Requirements
28 |
29 | - You have created a trial account on SAP Cloud Platform: [Get a Free Trial Account on SAP Cloud Platform](https://developers.sap.com/tutorials/hcp-create-trial-account.html).
30 | - You have installed the ABAP Development Tools (ADT). [Get the ABAP Development Tools (ADT)](https://tools.hana.ondemand.com/#abap), section „Procedure“.
31 | - You have prepared your ABAP Trial which can be easily be done via the [SAP Cloud Platform cockpit](https://cockpit.hanatrial.ondemand.com) in just 3 steps.
32 | - Click on Enter **Your Trial Account**.
33 | 
34 | - Click on **Boosters** in the menu on the left hand side
35 | - Choose the tile **Prepare an Account for ABAP Trial** and follow the wizard
36 | 
37 |
38 | For a detailed step-by-step description check out our [Onboarding Tutorial](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/720c423ef1a8498ab690cf0e5512ba50.html#loio720c423ef1a8498ab690cf0e5512ba50__Create_ABAP_Trial_Instance).
39 |
40 | ## Download and Installation
41 |
42 | You have to download and install the ABAP Development Tools (ADT) as described in section [Requirements](#requirements)
43 |
44 | ## Known Issues
45 |
46 | There are no known issues.
47 |
48 | ## Exercises
49 |
50 | These are the steps of our hands-ons session:
51 |
52 | - [Getting Started](exercises/ex0/)
53 | - [Connect to the system](exercises/ex0#connect-to-the-system)
54 | - [Import the helper class - required on non-trial systems](exercises/ex0#import-of-the-helper-class-dmocl_gen_dev268_artifacts)
55 | - [Exercise 1 - Generate a starter application](exercises/ex1/README.md)
56 | - [Generate the data model](exercises/ex1/README.md#generate-the-data-model)
57 | - [Publish service](exercises/ex1#publish-service)
58 | - [Check the generated repository objects](exercises/ex1#check-the-generated-repository-objects)
59 | - [Behavior Implementation](exercises/ex1#behavior-implementation)
60 | - [Summary](exercises/ex1#summary)
61 | - [Solution](exercises/ex1/sources)
62 |
63 | - [Exercise 2 - Consume an OData service](exercises/ex2/README.md)
64 | - [Create the service consumption model](exercises/ex2#create-the-service-consumption-model)
65 | - [Create a console application to test the OData service](exercises/ex2#create-a-console-application-to-test-the-odata-service)
66 | - [Create a custom entity and implement the query implementation class](exercises/ex2#create-a-custom-entity-and-implement-the-query-implementation-class)
67 | - [Create a custom entity](exercises/ex2#create-a-custom-entity)
68 | - [Implement the query implemenation class](exercises/ex2#implement-the-query-implemenation-class)
69 | - [Add the custom entity as a value help](exercises/ex2#add-the-custom-entity-as-a-value-help)
70 | - [Test the service](exercises/ex2#test-the-service)
71 | - [Summary](exercises/ex2#summary)
72 | - [Solution](exercises/ex2/sources)
73 |
74 | - [Exercise 3 - Consume a SOAP Web service](exercises/ex3/README.md)
75 | - [Download the WSDL](exercises/ex3#download-the-wsdl)
76 | - [Create the Service Consumption Model](exercises/ex3#create-the-service-consumption-model)
77 | - [Add and implement a determination](exercises/ex3/README.md#add-and-implement-a-determination)
78 | - [Test the service](exercises/ex3/README.md#test-the-service)
79 | - [Solution](exercises/ex3/sources)
80 |
81 |
82 | ## How to obtain support
83 |
84 | Support for the content in this repository is available during the actual time of the online session for which this content has been designed. Otherwise, you may request support via the [Issues](../../issues) tab.
85 |
86 | ## License
87 | Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](LICENSES/Apache-2.0.txt) file.
88 |
89 |
--------------------------------------------------------------------------------
/exercises/ex3/sources/EPM_PRODUCT_SOAP.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | false
10 |
11 |
12 |
13 |
14 | false
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | false
24 |
25 |
26 |
27 |
28 | false
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | false
39 |
40 |
41 | 0050568C901D1ED79182D1F2706880F5
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | no
50 | false
51 | true
52 | false
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
--------------------------------------------------------------------------------
/exercises/ex3/sources/ex3_WSDL.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | false
10 |
11 |
12 |
13 |
14 | false
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | false
24 |
25 |
26 |
27 |
28 | false
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | false
39 |
40 |
41 | 0050568C901D1ED79182D1F2706880F5
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | no
50 | false
51 | true
52 | false
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/exercises/ex1/sources/zcl_generate_dev268.txt:
--------------------------------------------------------------------------------
1 | CLASS zcl_generate_dev268_#### DEFINITION
2 | PUBLIC
3 | INHERITING FROM cl_xco_cp_adt_simple_classrun
4 | FINAL
5 | CREATE PUBLIC .
6 |
7 | PUBLIC SECTION.
8 |
9 | PROTECTED SECTION.
10 | METHODS main REDEFINITION.
11 | PRIVATE SECTION.
12 |
13 | DATA package_name TYPE sxco_package VALUE 'ZRAP_INVENTORY_####'.
14 | DATA unique_number TYPE string VALUE '####'.
15 | DATA table_name_inventory TYPE sxco_dbt_object_name.
16 | DATA dev_system_environment TYPE REF TO if_xco_cp_gen_env_dev_system.
17 | DATA transport TYPE sxco_transport .
18 |
19 |
20 | METHODS generate_table IMPORTING io_put_operation TYPE REF TO if_xco_cp_gen_d_o_put
21 | table_name TYPE sxco_dbt_object_name
22 | table_short_description TYPE if_xco_cp_gen_tabl_dbt_s_form=>tv_short_description .
23 |
24 | METHODS get_json_string RETURNING VALUE(json_string) TYPE string.
25 |
26 | ENDCLASS.
27 |
28 | CLASS zcl_generate_dev268_#### IMPLEMENTATION.
29 | METHOD main.
30 | DATA json_string TYPE string.
31 | json_string = get_json_string( ).
32 |
33 | package_name = to_upper( package_name ).
34 | DATA(lo_package) = xco_cp_abap_repository=>object->devc->for( package_name ).
35 |
36 | IF NOT lo_package->exists( ).
37 | RAISE EXCEPTION TYPE /dmo/cx_rap_generator
38 | EXPORTING
39 | textid = /dmo/cx_rap_generator=>package_does_not_exist
40 | mv_value = CONV #( package_name ).
41 | ENDIF.
42 |
43 | table_name_inventory = |ZRAP_INVEN_{ unique_number }|.
44 | DATA(lo_table) = xco_cp_abap_repository=>object->tabl->for( CONV #( table_name_inventory ) ).
45 |
46 | IF lo_table->exists( ) = abap_false.
47 |
48 | DATA(lv_package_software_component) = lo_package->read( )-property-software_component->name.
49 | DATA(lo_transport_layer) = lo_package->read( )-property-transport_layer.
50 | DATA(lo_transport_target) = lo_transport_layer->get_transport_target( ).
51 | DATA(lv_transport_target) = lo_transport_target->value.
52 | DATA(lo_transport_request) = xco_cp_cts=>transports->workbench( lo_transport_target->value )->create_request( | create tables | ).
53 | DATA(lv_transport) = lo_transport_request->value.
54 | transport = lv_transport.
55 | dev_system_environment = xco_cp_generation=>environment->dev_system( lv_transport ).
56 |
57 | DATA(lo_objects_put_operation) = dev_system_environment->create_put_operation( ).
58 |
59 | generate_table(
60 | EXPORTING
61 | io_put_operation = lo_objects_put_operation
62 | table_name = table_name_inventory
63 | table_short_description = | Inventory data group { unique_number }|
64 | ).
65 |
66 | DATA(lo_result) = lo_objects_put_operation->execute( ).
67 |
68 | out->write( | table { table_name_inventory } created| ).
69 |
70 | DATA(lo_findings) = lo_result->findings.
71 | DATA(lt_findings) = lo_findings->get( ).
72 |
73 | IF lt_findings IS NOT INITIAL.
74 | out->write( lt_findings ).
75 | ENDIF.
76 |
77 | ELSE.
78 | out->write( | table { table_name_inventory } already exists| ).
79 | ENDIF.
80 |
81 |
82 |
83 | "create RAP BO
84 |
85 | DATA(rap_generator) = NEW /dmo/cl_rap_generator( json_string ).
86 | DATA(todos) = rap_generator->generate_bo( ).
87 | DATA(rap_bo_name) = rap_generator->root_node->rap_root_node_objects-service_binding.
88 | out->write( |RAP BO { rap_bo_name } generated successfully| ).
89 | out->write( |Todo's:| ).
90 | LOOP AT todos INTO DATA(todo).
91 | out->write( todo ).
92 | ENDLOOP.
93 |
94 |
95 | ENDMETHOD.
96 |
97 |
98 | METHOD generate_table.
99 |
100 | DATA(lo_specification) = io_put_operation->for-tabl-for-database_table->add_object( table_name
101 | )->set_package( package_name
102 | )->create_form_specification( ).
103 |
104 | lo_specification->set_short_description( table_short_description ).
105 | lo_specification->set_delivery_class( xco_cp_database_table=>delivery_class->l ).
106 | lo_specification->set_data_maintenance( xco_cp_database_table=>data_maintenance->allowed ).
107 |
108 |
109 | DATA database_table_field TYPE REF TO if_xco_gen_tabl_dbt_s_fo_field .
110 |
111 | database_table_field = lo_specification->add_field( 'CLIENT' ).
112 | database_table_field->set_type( xco_cp_abap_dictionary=>data_element( 'MANDT' ) )->set_key_indicator( )->set_not_null( ).
113 |
114 | database_table_field = lo_specification->add_field( 'UUID' ).
115 | database_table_field->set_type( xco_cp_abap_dictionary=>data_element( 'SYSUUID_X16' ) )->set_key_indicator( )->set_not_null( ).
116 |
117 | database_table_field = lo_specification->add_field( 'INVENTORY_ID' ).
118 | database_table_field->set_type( xco_cp_abap_dictionary=>built_in_type->numc( 6 ) ).
119 |
120 | database_table_field = lo_specification->add_field( 'PRODUCT_ID' ).
121 | database_table_field->set_type( xco_cp_abap_dictionary=>built_in_type->char( 10 ) ).
122 |
123 |
124 | database_table_field = lo_specification->add_field( 'QUANTITY' ).
125 | database_table_field->set_type( xco_cp_abap_dictionary=>built_in_type->quan( iv_length = 13 iv_decimals = 3 ) ).
126 | database_table_field->currency_quantity->set_reference_table( CONV #( to_upper( table_name ) ) )->set_reference_field( 'QUANTITY_UNIT' ).
127 |
128 | database_table_field = lo_specification->add_field( 'QUANTITY_UNIT' ).
129 | database_table_field->set_type( xco_cp_abap_dictionary=>built_in_type->unit( 3 ) ).
130 |
131 | database_table_field = lo_specification->add_field( 'PRICE' ).
132 | database_table_field->set_type( xco_cp_abap_dictionary=>built_in_type->curr( iv_length = 16 iv_decimals = 2 ) ).
133 | database_table_field->currency_quantity->set_reference_table( CONV #( to_upper( table_name ) ) )->set_reference_field( 'CURRENCY_CODE' ).
134 |
135 | database_table_field = lo_specification->add_field( 'CURRENCY_CODE' ).
136 | database_table_field->set_type( xco_cp_abap_dictionary=>built_in_type->cuky ).
137 |
138 | database_table_field = lo_specification->add_field( 'REMARK' ).
139 | database_table_field->set_type( xco_cp_abap_dictionary=>built_in_type->char( 256 ) ).
140 |
141 | database_table_field = lo_specification->add_field( 'NOT_AVAILABLE' ).
142 | database_table_field->set_type( xco_cp_abap_dictionary=>data_element( 'ABAP_BOOLEAN' ) ).
143 |
144 | database_table_field = lo_specification->add_field( 'CREATED_BY' ).
145 | database_table_field->set_type( xco_cp_abap_dictionary=>data_element( 'SYUNAME' ) ).
146 |
147 | database_table_field = lo_specification->add_field( 'CREATED_AT' ).
148 | database_table_field->set_type( xco_cp_abap_dictionary=>data_element( 'TIMESTAMPL' ) ).
149 |
150 | database_table_field = lo_specification->add_field( 'LAST_CHANGED_BY' ).
151 | database_table_field->set_type( xco_cp_abap_dictionary=>data_element( 'SYUNAME' ) ).
152 |
153 | database_table_field = lo_specification->add_field( 'LAST_CHANGED_AT' ).
154 | database_table_field->set_type( xco_cp_abap_dictionary=>data_element( 'TIMESTAMPL' ) ).
155 |
156 | ENDMETHOD.
157 |
158 | METHOD get_json_string.
159 |
160 | json_string ='{' && |\r\n| &&
161 | ' "implementationType": "managed_uuid",' && |\r\n| &&
162 | ' "namespace": "Z",' && |\r\n| &&
163 | | "suffix": "_{ unique_number }",| && |\r\n| &&
164 | ' "prefix": "RAP_",' && |\r\n| &&
165 | | "package": "{ package_name }",| && |\r\n| &&
166 | ' "datasourcetype": "table",' && |\r\n| &&
167 | ' "bindingtype": "odata_v2_ui",' && |\r\n| &&
168 | | "transportrequest": "{ transport }",| && |\r\n| &&
169 | ' "hierarchy": {' && |\r\n| &&
170 | ' "entityName": "Inventory",' && |\r\n| &&
171 | | "dataSource": "zrap_inven_{ unique_number }",| && |\r\n| &&
172 | ' "objectId": "inventory_id" ' && |\r\n| &&
173 | ' }' && |\r\n| &&
174 | '}'.
175 |
176 | ENDMETHOD.
177 |
178 | ENDCLASS.
179 |
--------------------------------------------------------------------------------
/LICENSES/Apache-2.0.txt:
--------------------------------------------------------------------------------
1 | Apache License
2 |
3 | Version 2.0, January 2004
4 |
5 | http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION,
6 | AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 |
11 |
12 | "License" shall mean the terms and conditions for use, reproduction, and distribution
13 | as defined by Sections 1 through 9 of this document.
14 |
15 |
16 |
17 | "Licensor" shall mean the copyright owner or entity authorized by the copyright
18 | owner that is granting the License.
19 |
20 |
21 |
22 | "Legal Entity" shall mean the union of the acting entity and all other entities
23 | that control, are controlled by, or are under common control with that entity.
24 | For the purposes of this definition, "control" means (i) the power, direct
25 | or indirect, to cause the direction or management of such entity, whether
26 | by contract or otherwise, or (ii) ownership of fifty percent (50%) or more
27 | of the outstanding shares, or (iii) beneficial ownership of such entity.
28 |
29 |
30 |
31 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions
32 | granted by this License.
33 |
34 |
35 |
36 | "Source" form shall mean the preferred form for making modifications, including
37 | but not limited to software source code, documentation source, and configuration
38 | files.
39 |
40 |
41 |
42 | "Object" form shall mean any form resulting from mechanical transformation
43 | or translation of a Source form, including but not limited to compiled object
44 | code, generated documentation, and conversions to other media types.
45 |
46 |
47 |
48 | "Work" shall mean the work of authorship, whether in Source or Object form,
49 | made available under the License, as indicated by a copyright notice that
50 | is included in or attached to the work (an example is provided in the Appendix
51 | below).
52 |
53 |
54 |
55 | "Derivative Works" shall mean any work, whether in Source or Object form,
56 | that is based on (or derived from) the Work and for which the editorial revisions,
57 | annotations, elaborations, or other modifications represent, as a whole, an
58 | original work of authorship. For the purposes of this License, Derivative
59 | Works shall not include works that remain separable from, or merely link (or
60 | bind by name) to the interfaces of, the Work and Derivative Works thereof.
61 |
62 |
63 |
64 | "Contribution" shall mean any work of authorship, including the original version
65 | of the Work and any modifications or additions to that Work or Derivative
66 | Works thereof, that is intentionally submitted to Licensor for inclusion in
67 | the Work by the copyright owner or by an individual or Legal Entity authorized
68 | to submit on behalf of the copyright owner. For the purposes of this definition,
69 | "submitted" means any form of electronic, verbal, or written communication
70 | sent to the Licensor or its representatives, including but not limited to
71 | communication on electronic mailing lists, source code control systems, and
72 | issue tracking systems that are managed by, or on behalf of, the Licensor
73 | for the purpose of discussing and improving the Work, but excluding communication
74 | that is conspicuously marked or otherwise designated in writing by the copyright
75 | owner as "Not a Contribution."
76 |
77 |
78 |
79 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf
80 | of whom a Contribution has been received by Licensor and subsequently incorporated
81 | within the Work.
82 |
83 | 2. Grant of Copyright License. Subject to the terms and conditions of this
84 | License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
85 | no-charge, royalty-free, irrevocable copyright license to reproduce, prepare
86 | Derivative Works of, publicly display, publicly perform, sublicense, and distribute
87 | the Work and such Derivative Works in Source or Object form.
88 |
89 | 3. Grant of Patent License. Subject to the terms and conditions of this License,
90 | each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
91 | no-charge, royalty-free, irrevocable (except as stated in this section) patent
92 | license to make, have made, use, offer to sell, sell, import, and otherwise
93 | transfer the Work, where such license applies only to those patent claims
94 | licensable by such Contributor that are necessarily infringed by their Contribution(s)
95 | alone or by combination of their Contribution(s) with the Work to which such
96 | Contribution(s) was submitted. If You institute patent litigation against
97 | any entity (including a cross-claim or counterclaim in a lawsuit) alleging
98 | that the Work or a Contribution incorporated within the Work constitutes direct
99 | or contributory patent infringement, then any patent licenses granted to You
100 | under this License for that Work shall terminate as of the date such litigation
101 | is filed.
102 |
103 | 4. Redistribution. You may reproduce and distribute copies of the Work or
104 | Derivative Works thereof in any medium, with or without modifications, and
105 | in Source or Object form, provided that You meet the following conditions:
106 |
107 | (a) You must give any other recipients of the Work or Derivative Works a copy
108 | of this License; and
109 |
110 | (b) You must cause any modified files to carry prominent notices stating that
111 | You changed the files; and
112 |
113 | (c) You must retain, in the Source form of any Derivative Works that You distribute,
114 | all copyright, patent, trademark, and attribution notices from the Source
115 | form of the Work, excluding those notices that do not pertain to any part
116 | of the Derivative Works; and
117 |
118 | (d) If the Work includes a "NOTICE" text file as part of its distribution,
119 | then any Derivative Works that You distribute must include a readable copy
120 | of the attribution notices contained within such NOTICE file, excluding those
121 | notices that do not pertain to any part of the Derivative Works, in at least
122 | one of the following places: within a NOTICE text file distributed as part
123 | of the Derivative Works; within the Source form or documentation, if provided
124 | along with the Derivative Works; or, within a display generated by the Derivative
125 | Works, if and wherever such third-party notices normally appear. The contents
126 | of the NOTICE file are for informational purposes only and do not modify the
127 | License. You may add Your own attribution notices within Derivative Works
128 | that You distribute, alongside or as an addendum to the NOTICE text from the
129 | Work, provided that such additional attribution notices cannot be construed
130 | as modifying the License.
131 |
132 | You may add Your own copyright statement to Your modifications and may provide
133 | additional or different license terms and conditions for use, reproduction,
134 | or distribution of Your modifications, or for any such Derivative Works as
135 | a whole, provided Your use, reproduction, and distribution of the Work otherwise
136 | complies with the conditions stated in this License.
137 |
138 | 5. Submission of Contributions. Unless You explicitly state otherwise, any
139 | Contribution intentionally submitted for inclusion in the Work by You to the
140 | Licensor shall be under the terms and conditions of this License, without
141 | any additional terms or conditions. Notwithstanding the above, nothing herein
142 | shall supersede or modify the terms of any separate license agreement you
143 | may have executed with Licensor regarding such Contributions.
144 |
145 | 6. Trademarks. This License does not grant permission to use the trade names,
146 | trademarks, service marks, or product names of the Licensor, except as required
147 | for reasonable and customary use in describing the origin of the Work and
148 | reproducing the content of the NOTICE file.
149 |
150 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to
151 | in writing, Licensor provides the Work (and each Contributor provides its
152 | Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
153 | KIND, either express or implied, including, without limitation, any warranties
154 | or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR
155 | A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness
156 | of using or redistributing the Work and assume any risks associated with Your
157 | exercise of permissions under this License.
158 |
159 | 8. Limitation of Liability. In no event and under no legal theory, whether
160 | in tort (including negligence), contract, or otherwise, unless required by
161 | applicable law (such as deliberate and grossly negligent acts) or agreed to
162 | in writing, shall any Contributor be liable to You for damages, including
163 | any direct, indirect, special, incidental, or consequential damages of any
164 | character arising as a result of this License or out of the use or inability
165 | to use the Work (including but not limited to damages for loss of goodwill,
166 | work stoppage, computer failure or malfunction, or any and all other commercial
167 | damages or losses), even if such Contributor has been advised of the possibility
168 | of such damages.
169 |
170 | 9. Accepting Warranty or Additional Liability. While redistributing the Work
171 | or Derivative Works thereof, You may choose to offer, and charge a fee for,
172 | acceptance of support, warranty, indemnity, or other liability obligations
173 | and/or rights consistent with this License. However, in accepting such obligations,
174 | You may act only on Your own behalf and on Your sole responsibility, not on
175 | behalf of any other Contributor, and only if You agree to indemnify, defend,
176 | and hold each Contributor harmless for any liability incurred by, or claims
177 | asserted against, such Contributor by reason of your accepting any such warranty
178 | or additional liability. END OF TERMS AND CONDITIONS
179 |
180 | APPENDIX: How to apply the Apache License to your work.
181 |
182 | To apply the Apache License to your work, attach the following boilerplate
183 | notice, with the fields enclosed by brackets "[]" replaced with your own identifying
184 | information. (Don't include the brackets!) The text should be enclosed in
185 | the appropriate comment syntax for the file format. We also recommend that
186 | a file or class name and description of purpose be included on the same "printed
187 | page" as the copyright notice for easier identification within third-party
188 | archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 |
194 | you may not use this file except in compliance with the License.
195 |
196 | You may obtain a copy of the License at
197 |
198 | http://www.apache.org/licenses/LICENSE-2.0
199 |
200 | Unless required by applicable law or agreed to in writing, software
201 |
202 | distributed under the License is distributed on an "AS IS" BASIS,
203 |
204 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
205 |
206 | See the License for the specific language governing permissions and
207 |
208 | limitations under the License.
209 |
--------------------------------------------------------------------------------
/exercises/ex3/README.md:
--------------------------------------------------------------------------------
1 | # TOC
2 | [Home](../../README.md#exercises)
3 | # Exercise 3 - Consume a SOAP Web Service
4 |
5 | - [Download the WSDL](#download-the-wsdl)
6 | - [Create the Service Consumption Model](#create-the-service-consumption-model)
7 | - [Add and implement a determination](#add-and-implement-a-determination)
8 | - [Test the service](#test-the-service)
9 | - [Summary](#summary)
10 | - [Solution](#solution)
11 |
12 | In the following exercise you will learn how to call a SOAP web service and how to embed this into your inventory application by using it as part of a determination. The SOAP web service that we are going to use is a demo web service available on the SAP Gateway Demo system ES5.
13 |
14 | ## Download the WSDL
15 |
16 | 1. Create a text file with the extension .XML locally on your computer
17 | 2. Copy the content of the WSDL file into that file. The WSDL can be found here: [Link to WSDL](sources/ex3_WSDL.txt)
18 |
19 |
20 | ## Create the Service Consumption Model
21 |
22 | In this step we will create a service consumption model based on the WSDL file that you have downloaded in the previous step.
23 |
24 | 1. Navigate to the folder **Business Services > Service Consumption Models**
25 |
26 | 2. Right-click on the folder **Service Consumption Models** and choose **New Service Consumption Model**
27 |
28 | 
29 |
30 | 3. The New Service Consumption Model dialogue opens. Here enter the following data:
31 |
32 | Name: `ZSC_RAP_GETPRICE_####`
33 | Description: `Product price from ES5`
34 | Remote Consumption Model: `Web Service` (to be selected from the drop down box)
35 |
36 | 
37 |
38 | 4. The WSDL file of the SOAP web service that you want to consume must be uploaded in file format. If you have not yet downloaded the WSDL file you have to do this now.
39 |
40 | - Click **Browse** to select the WSDL file that you have downloaded earlier in this exercise
41 | - Prefix: **`ZRAP_####_`**
42 |
43 | 
44 |
45 | > **Caution**
46 | > Opposed to the prefix that we have chosen for **OData Service Consumption Proxy** we have to choose a leading **Z**.
47 | > If not, we get an error message that states:
48 | > *Package ZRAP_INVENTORY_#### is a customer package, object RAP_####_ is in SAP namespace. Use a valid combination of object name*
49 | > 
50 |
51 |
52 |
53 |
54 | 5. Selection of transport request
55 |
56 | - Select a transport request
57 | - Press **Finish**
58 |
59 | 
60 |
61 | 6. Service Consumption Model
62 |
63 | The Web Service does only have one service operation `get_price`.
64 |
65 | > **Please note**
66 | > The wizard provides code samples for each service operation. The code can be copied using the the *Copy to clipboard* button.
67 | > We will not do this since in this exercise since we have provided a detailed code sample (see below) which is however based on the code snippet mentioned above.
68 |
69 |
70 | 
71 |
72 | 7. Activate your changes
73 |
74 | Press the  button to generate the service consumption model alongside with all dependend objects.
75 |
76 | 8. Check generated objects
77 |
78 | When refreshing your package in the *Project Explorer* you will notice that several objects have been generated. For those that are used to the generation of SOAP Web Service proxies in on premise systems they will look familiar.
79 |
80 | 
81 |
82 |
83 |
84 | ## Add and implement a determination
85 |
86 | 1. Add a determination in the **behavior definition**
87 |
88 | - Open your behavior definition `ZI_RAP_INVENTORY_####`
89 | - Add the following code snippet to add a determination for the field `Price`
90 |
91 |
92 | determination GetPrice on modify { field ProductID; }
93 |
94 |
95 | 
96 |
97 | - Select the determination name `GetPrice` and press **CTRL+1** for a quick fix
98 | - Double click on the quick fix **Add missing method for determination GetPrice in local handler class ...**
99 |
100 | 
101 |
102 | 2. Add the following code in the implementation of the method `GetPrice`.
103 |
104 | > **Coding explained**
105 | > The following code is using large parts of the code snippets provided by the service consumption model.
106 | > It has however been adjusted to fit our needs.
107 | > 1. The destination is not retrieved by calling the method `cl_soap_destination_provider=>create_by_cloud_destination( )` but by using the method `cl_soap_destination_provider=>create_by_url( )`. This is because the destination service is not available in the ABAP trial systems in SAP Cloud Platform.
108 | > 2. Instead of using an inline declaration for `destination`and `proxy` these variables are defined beforehand. This way we can avoid that the destination and proxy object are created several times in case multiple inventories are to be created.
109 | > 3. The data retrieved from the SOAP call is used to update the inventory data via EML.
110 |
111 | > **Do not forget to search and replace the placeholder `####` with the unique number that you have chosen beforehand.**
112 |
113 |
114 |
115 | METHOD GetPrice.
116 |
117 | DATA destination TYPE REF TO if_soap_destination.
118 | DATA proxy TYPE REF TO zrap_####_co_epm_product_soap .
119 | DATA reported_inventory_soap LIKE reported-inventory.
120 | "Ensure idempotence
121 | READ ENTITIES OF zi_rap_inventory_#### IN LOCAL MODE
122 | ENTITY Inventory
123 | FIELDS ( Price ProductID )
124 | WITH CORRESPONDING #( keys )
125 | RESULT DATA(inventories).
126 |
127 | DELETE inventories WHERE Price IS NOT INITIAL.
128 | CHECK inventories IS NOT INITIAL.
129 |
130 | DELETE inventories WHERE ProductID =''.
131 | CHECK inventories IS NOT INITIAL.
132 |
133 | LOOP AT inventories ASSIGNING FIELD-SYMBOL(<inventory>).
134 |
135 | TRY.
136 |
137 | IF destination IS INITIAL.
138 | destination = cl_soap_destination_provider=>create_by_url( i_url = 'https://sapes5.sapdevcenter.com/sap/bc/srt/xip/sap/zepm_product_soap/002/epm_product_soap/epm_product_soap' ).
139 | ENDIF.
140 | IF proxy IS INITIAL.
141 | proxy = NEW zrap_####_co_epm_product_soap(
142 | destination = destination
143 | ).
144 | ENDIF.
145 |
146 | DATA(request) = VALUE zrap_####_req_msg_type( req_msg_type-product = <inventory>-ProductID ).
147 | proxy->get_price(
148 | EXPORTING
149 | input = request
150 | IMPORTING
151 | output = DATA(response)
152 | ).
153 |
154 | <inventory>-Price = response-res_msg_type-price .
155 | <inventory>-CurrencyCode = response-res_msg_type-currency.
156 | "handle response
157 |
158 | CATCH cx_soap_destination_error INTO DATA(soap_destination_error).
159 | DATA(error_message) = soap_destination_error->get_text( ).
160 | CATCH cx_ai_system_fault INTO DATA(ai_system_fault).
161 | error_message = | code: { ai_system_fault->code } codetext: { ai_system_fault->codecontext } |.
162 | CATCH zrap_####_cx_fault_msg_type INTO DATA(soap_exception).
163 | error_message = soap_exception->error_text.
164 | "fill reported structure to be displayed on the UI
165 | APPEND VALUE #( uuid = <inventory>-uuid
166 | %msg = new_message( id = 'ZCM_RAP_GENERATOR'
167 | number = '016'
168 | v1 = error_message
169 | "v2 = messages[ 1 ]-msgv2
170 | "v3 = messages[ 1 ]-msgv3
171 | "v4 = messages[ 1 ]-msgv4
172 | severity = CONV #( 'E' ) )
173 | %element-price = if_abap_behv=>mk-on
174 |
175 |
176 | ) TO reported_inventory_soap.
177 | "inventory entries where no price could be retrieved must not be passed to the MODIFY statement
178 | DELETE inventories INDEX sy-tabix.
179 | ENDTRY.
180 |
181 | ENDLOOP.
182 |
183 | "update involved instances
184 | MODIFY ENTITIES OF zi_rap_inventory_#### IN LOCAL MODE
185 | ENTITY Inventory
186 | UPDATE FIELDS ( Price CurrencyCode )
187 | WITH VALUE #( FOR inventory IN inventories (
188 | %tky = inventory-%tky
189 | Price = inventory-Price
190 | CurrencyCode = inventory-CurrencyCode
191 | ) )
192 | REPORTED DATA(reported_entities).
193 |
194 | "fill reported
195 | reported = CORRESPONDING #( DEEP reported_entities ).
196 |
197 | "add reported from SOAP call
198 | LOOP AT reported_inventory_soap INTO DATA(reported_inventory).
199 | APPEND reported_inventory TO reported-inventory.
200 | ENDLOOP.
201 |
202 |
203 | ENDMETHOD.
204 |
205 |
206 |
207 | 3. Activate your changes.
208 |
209 | ## Test the service
210 |
211 | 1. Test service with Fiori Elements preview.
212 |
213 | - Open the service binding ZUI_RAP_INVENTORY_####_02 (either via Ctrl+Shift+A or via navigation in the Project Explorer)
214 | - Select the entity `Ìnventory`.
215 | - Press the **Preview** button
216 |
217 | 
218 | 2. Create a new inventory entry and select a valid product id using the value help
219 |
220 | - Select a valid ProductID via the value help (e.g. HT-1000)
221 |
222 | 
223 |
224 | 3. Press the **Create** button
225 |
226 | - When pressing the **Create** button the determination for the price will call the SOAP service
227 | - The inventory will be created with the price and the currency retrieved from the backend
228 |
229 | 
230 |
231 | 4. Create an inventory entry with an invalid ProductID (e.g. www).
232 |
233 | - Enter an invalid ProductID, e.g. `www`
234 |
235 | 
236 |
237 | - The SOAP call will not be able to find the ProductId in the backend and will hence respond with the error message `Product not found. Try e.g. HT-1000 :)`.
238 |
239 | 
240 |
241 | ## Summary
242 |
243 | In this session you have learned how you can use SAP Cloud Platform, ABAP environment to implement a side-by-side extension scenarios for an SAP S/4 HANA system using the ABAP RESTful Application Programming Model.
244 |
245 | You have retrieved data from the SAP S/4HANA system using OData and SOAP based communication to implement
246 |
247 | - a value help to select a product for an inventory entry
248 | - a determination for the price of a product
249 |
250 | 
251 |
252 | In a licensed SAP Cloud Platform, ABAP Environment system you would also be able to create a service consumption model for RFC function modules.
253 |
254 | ## Solution
255 |
256 | [Source code used in this exercise](sources)
257 |
--------------------------------------------------------------------------------
/src/#dmo#cl_gen_dev268_artifacts.clas.abap:
--------------------------------------------------------------------------------
1 | CLASS /dmo/cl_gen_dev268_artifacts DEFINITION
2 | PUBLIC
3 | INHERITING FROM cl_xco_cp_adt_simple_classrun
4 | FINAL
5 | CREATE PUBLIC .
6 |
7 | PUBLIC SECTION.
8 |
9 | PROTECTED SECTION.
10 | METHODS main REDEFINITION.
11 | PRIVATE SECTION.
12 |
13 | CONSTANTS:
14 | co_prefix TYPE string VALUE 'ZRAP_INVENTORY_',
15 | co_zlocal_package TYPE sxco_package VALUE 'ZLOCAL',
16 | co_session_name TYPE string VALUE 'DEV268'.
17 |
18 |
19 | DATA package_name TYPE sxco_package VALUE 'ZRAP_INVENTORY_####'.
20 | DATA unique_number TYPE string VALUE '####'.
21 | DATA table_name_inventory TYPE sxco_dbt_object_name.
22 | DATA dev_system_environment TYPE REF TO if_xco_cp_gen_env_dev_system.
23 | DATA transport TYPE sxco_transport .
24 | DATA transport_request TYPE sxco_transport.
25 |
26 | METHODS generate_table IMPORTING io_put_operation TYPE REF TO if_xco_cp_gen_d_o_put
27 | table_name TYPE sxco_dbt_object_name
28 | table_short_description TYPE if_xco_cp_gen_tabl_dbt_s_form=>tv_short_description .
29 |
30 | METHODS get_json_string RETURNING VALUE(json_string) TYPE string.
31 |
32 | METHODS get_unique_suffix IMPORTING VALUE(s_prefix) TYPE string RETURNING VALUE(s_unique_suffix) TYPE string.
33 | METHODS create_transport RETURNING VALUE(lo_transport) TYPE sxco_transport.
34 | METHODS create_package IMPORTING VALUE(lo_transport) TYPE sxco_transport.
35 |
36 |
37 | ENDCLASS.
38 |
39 |
40 |
41 | CLASS /dmo/cl_gen_dev268_artifacts IMPLEMENTATION.
42 |
43 | METHOD main.
44 | DATA json_string TYPE string.
45 |
46 |
47 | unique_number = get_unique_suffix( co_prefix ).
48 |
49 | package_name = |ZRAP_INVENTORY_{ unique_number }|.
50 |
51 | package_name = to_upper( package_name ).
52 |
53 | out->write( | BEGIN OF GENERATION ({ cl_abap_context_info=>get_system_date( ) } { cl_abap_context_info=>get_system_time( ) } UTC) ... | ).
54 | out->write( | - Package: { package_name } | ).
55 | out->write( | - Group ID: { unique_number } | ).
56 |
57 | "create transport
58 | transport_request = create_transport( ).
59 | "create package
60 | create_package( transport_request ).
61 |
62 | json_string = get_json_string( ).
63 |
64 | DATA(lo_package) = xco_cp_abap_repository=>object->devc->for( package_name ).
65 | *
66 | * IF NOT lo_package->exists( ).
67 | * RAISE EXCEPTION TYPE /dmo/cx_rap_generator
68 | * EXPORTING
69 | * textid = /dmo/cx_rap_generator=>package_does_not_exist
70 | * mv_value = CONV #( package_name ).
71 | * ENDIF.
72 |
73 | table_name_inventory = |ZRAP_INVEN_{ unique_number }|.
74 | DATA(lo_table) = xco_cp_abap_repository=>object->tabl->for( CONV #( table_name_inventory ) ).
75 |
76 | IF lo_table->exists( ) = abap_false.
77 |
78 | * DATA(lv_package_software_component) = lo_package->read( )-property-software_component->name.
79 | * DATA(lo_transport_layer) = lo_package->read( )-property-transport_layer.
80 | * DATA(lo_transport_target) = lo_transport_layer->get_transport_target( ).
81 | * DATA(lv_transport_target) = lo_transport_target->value.
82 | * DATA(lo_transport_request) = xco_cp_cts=>transports->workbench( lo_transport_target->value )->create_request( | create tables | ).
83 | * DATA(lv_transport) = lo_transport_request->value.
84 | * transport = lv_transport.
85 | * dev_system_environment = xco_cp_generation=>environment->dev_system( lv_transport ).
86 |
87 | dev_system_environment = xco_cp_generation=>environment->dev_system( transport_request ).
88 |
89 | DATA(lo_objects_put_operation) = dev_system_environment->create_put_operation( ).
90 |
91 | generate_table(
92 | EXPORTING
93 | io_put_operation = lo_objects_put_operation
94 | table_name = table_name_inventory
95 | table_short_description = | Inventory data group { unique_number }|
96 | ).
97 |
98 | DATA(lo_result) = lo_objects_put_operation->execute( ).
99 |
100 | out->write( | table { table_name_inventory } created| ).
101 |
102 | DATA(lo_findings) = lo_result->findings.
103 | DATA(lt_findings) = lo_findings->get( ).
104 |
105 | IF lt_findings IS NOT INITIAL.
106 | out->write( lt_findings ).
107 | ENDIF.
108 |
109 | ELSE.
110 | out->write( | table { table_name_inventory } already exists| ).
111 | ENDIF.
112 |
113 |
114 |
115 | "create RAP BO
116 |
117 | DATA(rap_generator) = NEW /dmo/cl_rap_generator( json_string ).
118 | DATA(todos) = rap_generator->generate_bo( ).
119 | DATA(rap_bo_name) = rap_generator->root_node->rap_root_node_objects-service_binding.
120 | out->write( |RAP BO { rap_bo_name } generated successfully| ).
121 | out->write( |Todo's:| ).
122 | LOOP AT todos INTO DATA(todo).
123 | out->write( todo ).
124 | ENDLOOP.
125 |
126 |
127 | ENDMETHOD.
128 |
129 |
130 | METHOD generate_table.
131 |
132 | DATA(lo_specification) = io_put_operation->for-tabl-for-database_table->add_object( table_name
133 | )->set_package( package_name
134 | )->create_form_specification( ).
135 |
136 | lo_specification->set_short_description( table_short_description ).
137 | lo_specification->set_delivery_class( xco_cp_database_table=>delivery_class->l ).
138 | lo_specification->set_data_maintenance( xco_cp_database_table=>data_maintenance->allowed ).
139 |
140 |
141 | DATA database_table_field TYPE REF TO if_xco_gen_tabl_dbt_s_fo_field .
142 |
143 | database_table_field = lo_specification->add_field( 'CLIENT' ).
144 | database_table_field->set_type( xco_cp_abap_dictionary=>data_element( 'MANDT' ) )->set_key_indicator( )->set_not_null( ).
145 |
146 | database_table_field = lo_specification->add_field( 'UUID' ).
147 | database_table_field->set_type( xco_cp_abap_dictionary=>data_element( 'SYSUUID_X16' ) )->set_key_indicator( )->set_not_null( ).
148 |
149 | database_table_field = lo_specification->add_field( 'INVENTORY_ID' ).
150 | database_table_field->set_type( xco_cp_abap_dictionary=>built_in_type->numc( 6 ) ).
151 |
152 | database_table_field = lo_specification->add_field( 'PRODUCT_ID' ).
153 | database_table_field->set_type( xco_cp_abap_dictionary=>built_in_type->char( 10 ) ).
154 |
155 |
156 | database_table_field = lo_specification->add_field( 'QUANTITY' ).
157 | database_table_field->set_type( xco_cp_abap_dictionary=>built_in_type->quan( iv_length = 13 iv_decimals = 3 ) ).
158 | database_table_field->currency_quantity->set_reference_table( CONV #( to_upper( table_name ) ) )->set_reference_field( 'QUANTITY_UNIT' ).
159 |
160 | database_table_field = lo_specification->add_field( 'QUANTITY_UNIT' ).
161 | database_table_field->set_type( xco_cp_abap_dictionary=>built_in_type->unit( 3 ) ).
162 |
163 | database_table_field = lo_specification->add_field( 'PRICE' ).
164 | database_table_field->set_type( xco_cp_abap_dictionary=>built_in_type->curr( iv_length = 16 iv_decimals = 2 ) ).
165 | database_table_field->currency_quantity->set_reference_table( CONV #( to_upper( table_name ) ) )->set_reference_field( 'CURRENCY_CODE' ).
166 |
167 | database_table_field = lo_specification->add_field( 'CURRENCY_CODE' ).
168 | database_table_field->set_type( xco_cp_abap_dictionary=>built_in_type->cuky ).
169 |
170 | database_table_field = lo_specification->add_field( 'REMARK' ).
171 | database_table_field->set_type( xco_cp_abap_dictionary=>built_in_type->char( 256 ) ).
172 |
173 | database_table_field = lo_specification->add_field( 'NOT_AVAILABLE' ).
174 | database_table_field->set_type( xco_cp_abap_dictionary=>data_element( 'ABAP_BOOLEAN' ) ).
175 |
176 | database_table_field = lo_specification->add_field( 'CREATED_BY' ).
177 | database_table_field->set_type( xco_cp_abap_dictionary=>data_element( 'SYUNAME' ) ).
178 |
179 | database_table_field = lo_specification->add_field( 'CREATED_AT' ).
180 | database_table_field->set_type( xco_cp_abap_dictionary=>data_element( 'TIMESTAMPL' ) ).
181 |
182 | database_table_field = lo_specification->add_field( 'LAST_CHANGED_BY' ).
183 | database_table_field->set_type( xco_cp_abap_dictionary=>data_element( 'SYUNAME' ) ).
184 |
185 | database_table_field = lo_specification->add_field( 'LAST_CHANGED_AT' ).
186 | database_table_field->set_type( xco_cp_abap_dictionary=>data_element( 'TIMESTAMPL' ) ).
187 |
188 | ENDMETHOD.
189 |
190 | METHOD get_json_string.
191 |
192 | json_string ='{' && |\r\n| &&
193 | ' "implementationType": "managed_uuid",' && |\r\n| &&
194 | ' "namespace": "Z",' && |\r\n| &&
195 | | "suffix": "_{ unique_number }",| && |\r\n| &&
196 | ' "prefix": "RAP_",' && |\r\n| &&
197 | | "package": "{ package_name }",| && |\r\n| &&
198 | ' "datasourcetype": "table",' && |\r\n| &&
199 | ' "bindingtype": "odata_v2_ui",' && |\r\n| &&
200 | | "transportrequest": "{ transport_request }",| && |\r\n| &&
201 | ' "hierarchy": {' && |\r\n| &&
202 | ' "entityName": "Inventory",' && |\r\n| &&
203 | | "dataSource": "zrap_inven_{ unique_number }",| && |\r\n| &&
204 | ' "objectId": "inventory_id" ' && |\r\n| &&
205 | ' }' && |\r\n| &&
206 | '}'.
207 |
208 | ENDMETHOD.
209 |
210 |
211 | METHOD create_package.
212 | DATA(lo_put_operation) = xco_cp_generation=>environment->dev_system( lo_transport )->for-devc->create_put_operation( ).
213 | DATA(lo_specification) = lo_put_operation->add_object( package_name )->create_form_specification( ).
214 | lo_specification->set_short_description( |{ co_session_name } tutorial package - { unique_number }| ).
215 | lo_specification->properties->set_super_package( co_zlocal_package )->set_software_component( co_zlocal_package ).
216 | lo_put_operation->execute( ).
217 | ENDMETHOD.
218 |
219 | METHOD create_transport.
220 | DATA(ls_package) = xco_cp_abap_repository=>package->for( co_zlocal_package )->read( ).
221 | DATA(lv_transport_layer) = ls_package-property-transport_layer->value.
222 | DATA(lv_transport_target) = ls_package-property-transport_layer->get_transport_target( )->value.
223 | DATA(lo_transport_request) = xco_cp_cts=>transports->workbench( lv_transport_target )->create_request( |{ co_session_name } generated tranport request - { unique_number }| ).
224 |
225 | * IF lo_transport_request->get_status( ) = xco_cp_transport=>filter->status( xco_cp_transport=>status->modifiable ).
226 | * DATA(lo_transport_modifiable) = abap_true.
227 | * ENDIF.
228 |
229 | lo_transport = lo_transport_request->value.
230 | ENDMETHOD.
231 |
232 | METHOD get_unique_suffix.
233 | DATA: li_counter(4) TYPE n,
234 | ls_counter TYPE string,
235 | ls_package_name TYPE sxco_package,
236 | is_valid_package TYPE abap_bool.
237 |
238 |
239 | s_unique_suffix = ''.
240 | is_valid_package = abap_false.
241 | li_counter = 0.
242 | ls_counter = li_counter.
243 | ls_package_name = s_prefix && ls_counter.
244 |
245 | WHILE is_valid_package = abap_false.
246 | "check package name
247 | DATA(lo_package) = xco_cp_abap_repository=>object->devc->for( ls_package_name ).
248 | IF NOT lo_package->exists( ).
249 | is_valid_package = abap_true.
250 | s_unique_suffix = ls_counter.
251 | ENDIF.
252 | li_counter = li_counter + 1.
253 | ls_counter = li_counter.
254 | ls_package_name = s_prefix && ls_counter.
255 | ENDWHILE.
256 | ENDMETHOD.
257 |
258 | ENDCLASS.
259 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/exercises/ex1/README.md:
--------------------------------------------------------------------------------
1 |
2 | [Home](../../README.md#exercises)
3 |
4 | # Exercise 1
5 |
6 |
7 | - [Generate the data model](#generate-the-data-model)
8 | - [Publish service](#publish-service)
9 | - [Check the generated repository objects](#check-the-generated-repository-objects)
10 | - [Behavior Implementation](#behavior-implementation)
11 | - [Summary](#summary)
12 | - [Solution](sources)
13 |
14 | In this exercise, we will create a starter application to collect inventory data.
15 |
16 | The usual process of development would be that you as a developer would now start to manually create the following repository objects for each entity
17 |
18 | - Table
19 | - CDS interface view
20 | - CDS projection view
21 | - Metadata Extension view
22 | - Behavior definition
23 | - Behavior implementation
24 |
25 | before you can start with the implementation of the business logic.
26 |
27 | In the ABAP trial systems we have thus prepared a helper class **/dmo/cl_gen_dev268_artifacts** to generate the database table to store the inventory data and different CDS artefacts needed for the next exercises.
28 |
29 | Since this is a green field scenario the application will be implemented using a **managed business object** that is based on the **ABAP RESTful Application Programming Model (RAP)**.
30 |
31 | This application will then be enhanced such that it leverages OData service calls and SOAP calls to retrieve data from a SAP S/4HANA backend. These services are either called as a value help or to perform a determination for the price of a product whenthe inventory data is created or updated.
32 |
33 | ## Generate the data model
34 |
35 | 1. Select the **Open ABAP Development Object** icon or press **Ctrl+Shift+A**.
36 |
37 | 
38 |
39 | 2. In the *Open ABAP Development Object* dialogue enter **/dmo/cl_gen_dev268_artifacts** as search string and press **OK**.
40 |
41 | 
42 |
43 | 2. The class **/dmo/cl_gen_dev268_artifacts** is displayed in a new tab.
44 |
45 | 
46 |
47 | 3. Press **F9** to run the ABAP class as a console application. As a result, you will see a success message in the Console.
48 |
49 | 
50 |
51 | 4. Please note down your group ID **`####`** and copy the name of the newly created package **ZRAP_INVENTORY_####**
52 |
53 | ...
54 | - Package: ZRAP_INVENTORY_####
55 | - Group ID: ####
56 | ...
57 |
58 |
59 | 5. Right click on the folder **Favorite Packages** and select **Add Package...**.
60 |
61 | 
62 |
63 | 6. Enter the name of your package **ZRAP_INVENTORY_####** and press **OK**.
64 |
65 |
66 | ## Publish service
67 |
68 | 1. The helper class **/dmo/cl_gen_dev268_artifacts** has done the following:
69 |
70 | - Using the XCO framework it has created a table to store the inventory data
71 | - It then has called the RAP Genertor which has generated the following repository objects for your convenience based on the table that has been generated beforehand
72 |
73 | Business Services
74 | - ZUI_RAP_INVENTORY_####_02 - Service Binding
75 | - ZUI_RAP_INVENTORY_#### - Service Definition
76 |
77 | CDS views
78 | - ZC_RAP_INVENTORY_#### - Projection view
79 | - ZI_RAP_INVENTORY_#### - Interface view
80 |
81 | Metadata Extension
82 | - ZC_RAP_INVENTORY_#### - MDE for the projection view
83 |
84 | Behavior Defintion
85 | - ZC_RAP_INVENTORY_#### - for the projection view
86 | - ZI_RAP_INVENTORY_#### - for the interface view
87 |
88 |
89 | > What is now left is to publish the service binding since this can not be automated (yet).
90 |
91 |
92 | 2. Open the service binding and double click on **ZUI_RAP_INVENTORY_####_O2**
93 | (in older versions of the RAP Generator it reads _02 instead of _O2)
94 |
95 | 
96 |
97 | 3. Click on **Publish** to publish the Service Binding.
98 |
99 | 
100 |
101 | 4. Select the entity **Inventory** and press the **Preview** button to start the *Fiori Elements Preview*.
102 |
103 | (The service also contains an entity I_Currency since the RAP Generator has added a value help for Currencies to the projection view.)
104 |
105 | 
106 |
107 | 5. Check the Fiori Elements Preview App. You will notice that we got a nearly full fledged UI with capabilities for
108 |
109 | - Searching
110 | - Filtering
111 | - Create and Delete inventory data
112 | - Update, visible when having created data
113 |
114 | This is because all possible behaviors (create, update and delete) have been enabled by default in our generated code.
115 | You will see that all CRUD operations are working out of the box (apart from calculating the inventory id, which we will do in a second).
116 | In addition all columns of the table are displayed by default as well since we have generated appropriate UI annoations.
117 | If you do not want to see all columns (either on the list- or the object page) you can comment out these annotations.
118 | This is however much simpler than having to write all these annotations from scratch.
119 |
120 | 16. You can try and start entering values for your first inventory item.
121 | However no checks nor any value help have been implemented yet.
122 | Especially not for the determination of the semantic key **InventoryId**.
123 |
124 | This we will do in the next step.
125 |
126 |
127 | 
128 |
129 | ## Check the generated repository objects
130 |
131 | The **interface view ZI_RAP_Inventory_####** was generated such that based on the ABAP field names aliases have been created such that the ABAP field name was converted into camelCase notation.
132 |
133 |
134 | define root view entity ZI_RAP_INVENTORY_1234
135 | as select from zrap_inven_1234
136 | {
137 | key UUID as UUID,
138 | INVENTORY_ID as InventoryID,
139 | PRODUCT_ID as ProductID,
140 | @Semantics.quantity.unitOfMeasure: 'QuantityUnit'
141 | QUANTITY as Quantity,
142 | QUANTITY_UNIT as QuantityUnit,
143 | ...
144 | }
145 |
146 |
147 | The **projection view ZC_RAP_Inventory_####** was generated such that it contains annotations for **search** and a value help for the field **CurrencyCode**.
148 |
149 |
150 | define root view entity ZC_RAP_INVENTORY_####
151 | as projection on ZI_RAP_Inventory_####
152 | {
153 | @Search.defaultSearchElement: true
154 | key UUID,
155 |
156 | @Search.defaultSearchElement: true
157 | InventoryID,
158 |
159 | ProductID,
160 |
161 | Quantity,
162 |
163 | QuantityUnit,
164 |
165 | @Semantics.amount.currencyCode: 'CurrencyCode'
166 | Price,
167 |
168 | @Consumption.valueHelpDefinition: [ {
169 | entity: {
170 | name: 'I_Currency',
171 | element: 'Currency'
172 | }
173 | } ]
174 | CurrencyCode,
175 |
176 |
177 | The **behavior definion ZI_RAP_Inventory_####** was generated such that the field **InventoryID** which acts as a semantic key was marked as readonly.
178 |
179 |
180 | field ( readonly ) InventoryID;
181 |
182 |
183 | also a mapping was added that maps the ABAP field names to the field names of the CDS views.
184 |
185 |
186 | mapping for zrap_inven_1234
187 | {
188 | UUID = UUID;
189 | InventoryID = INVENTORY_ID;
190 | ProductID = PRODUCT_ID;
191 | Quantity = QUANTITY;
192 | QuantityUnit = QUANTITY_UNIT;
193 | Remark = REMARK;
194 | NotAvailable = NOT_AVAILABLE;
195 | CreatedBy = CREATED_BY;
196 | CreatedAt = CREATED_AT;
197 | LastChangedBy = LAST_CHANGED_BY;
198 | LastChangedAt = LAST_CHANGED_AT;
199 | }
200 |
201 |
202 | And we find a determination that was generated for the semantic key field (that has to be implemented though).
203 |
204 | Please make sure that the determination that is performed during the **'save*** sequence for the InventoryID is triggered by **'create'** operation.
205 | *(in older versions the RAP Generator created a determination that acts on the modify operation)*
206 |
207 |
208 | determination CalculateInventoryID on save { create; }
209 |
210 |
211 | ## Change the generated code of the Metadata Extension File
212 |
213 | Last but not least, you will find it handy that a **Metadata Extension View ZC_RAP_Inventory_####** has also been generated that automatically publishes all field on the list page as well as on the object page by setting appropriate **@UI** annotations.
214 |
215 | Also the administrative fields like created_at as well as the UUID based key field are hidden by setting **@UI.hidden** to true.
216 |
217 | In the version of the RAP Generator which is currently deployed to SAP BTP ABAP evnironment trial ualso the fields **CurrencyCode** and **QuantityUnit** have been marked as **@UI.hidden**.
218 |
219 | Please change the code such that you remove the annotation **@UI.hidden** for QuantityUnit and CurrencyCode so that the code now reads:
220 |
221 | - QuantityUnit
222 |
223 |
224 | @UI.lineItem: [ {
225 | position: 50 ,
226 | importance: #HIGH,
227 | label: 'Unit'
228 | } ]
229 | @UI.identification: [ {
230 | position: 50 ,
231 | label: 'Unit'
232 | } ]
233 | QuantityUnit;
234 |
235 |
236 | - CurrencyCode
237 |
238 |
239 | @UI.lineItem: [ {
240 | position: 70 ,
241 | importance: #HIGH,
242 | label: 'Currency'
243 | } ]
244 | @UI.identification: [ {
245 | position: 70 ,
246 | label: 'Currency'
247 | } ]
248 | CurrencyCode;
249 |
250 |
251 | - Do not forget to **Activate** your changes.
252 |
253 | ## Behavior Implementation
254 |
255 | 1. In the **Project Explorer** navigate to **Source Code Library > Classes** and double click on **ZBP_I_RAP_INVENTORY_####**
256 |
257 | 
258 |
259 | 2. Navigate to the tab **Local Types**
260 |
261 | In the source code of the local class you will see that there is one method called **calculateinventoryid**.
262 |
263 | 3. Add the code shown below to implement the determination for the field **InventoryID**
264 |
265 | The code of the behavior implementation contains already an (empty) implementation for the determiniation that shall calculate the semantic key InventoryID.
266 |
267 | The implementation of the behavior defintion must (for technical reasons) take place in local classes that follow the naming convention **lhc_\** (here **lhc_Inventory**).
268 | We suggest to use the source code shown below to implement the calculation of the semantic key of our managed business object for inventory data. In a productive application you would rather use a number range.
269 | To keep our implementation simple we will use the approach to simply count the number of objects that are available.
270 | By a simple increment of this number we get a semantic key which is readable by the users of our application.
271 |
272 |
273 |
274 |
275 |
276 | METHOD CalculateInventoryID.
277 |
278 | "Ensure idempotence
279 | READ ENTITIES OF zi_rap_inventory_#### IN LOCAL MODE
280 | ENTITY Inventory
281 | FIELDS ( InventoryID )
282 | WITH CORRESPONDING #( keys )
283 | RESULT DATA(inventories).
284 |
285 | DELETE inventories WHERE InventoryID IS NOT INITIAL.
286 | CHECK inventories IS NOT INITIAL.
287 |
288 | "Get max travelID
289 | SELECT SINGLE FROM zrap_inven_#### FIELDS MAX( inventory_id ) INTO @DATA(max_inventory).
290 |
291 | "update involved instances
292 | MODIFY ENTITIES OF zi_rap_inventory_#### IN LOCAL MODE
293 | ENTITY Inventory
294 | UPDATE FIELDS ( InventoryID )
295 | WITH VALUE #( FOR inventory IN inventories INDEX INTO i (
296 | %tky = inventory-%tky
297 | inventoryID = max_inventory + i ) )
298 | REPORTED DATA(lt_reported).
299 |
300 | "fill reported
301 | reported = CORRESPONDING #( DEEP lt_reported ).
302 |
303 | ENDMETHOD.
304 |
305 |
306 |
307 | 7. Replace the placeholders #### with your group number and activate your changes **(Ctrl+F3)**
308 |
309 | 
310 |
311 | 8. Test the implementation.
312 |
313 | - Start the Fiori Elements preview and press the **Create** button.
314 | - Enter an arbritray product name
315 | - Press **Save**
316 |
317 | 
318 |
319 | 9. Check the numbering for your semantic key
320 |
321 |
322 | 
323 |
324 |
325 |
326 | ## Summary
327 |
328 | You have completed the exercise!
329 |
330 | You are now able to:
331 | - Implement Behavior Definitions to enable create, update and delete operations and make fields read-only Implement Behavior Implementations so that ABAP code in determinations is run when an object is created.
332 | - Use the Fiori Elements preview to test your service
333 |
334 |
335 | Continue with - [Exercise 2](../ex2/README.md)
336 |
337 |
--------------------------------------------------------------------------------
/exercises/ex2/README.md:
--------------------------------------------------------------------------------
1 | # TOC
2 | [Home](../../README.md#exercises)
3 | # Exercise 2
4 |
5 | - [Create the service consumption model](#create-the-service-consumption-model)
6 | - [Create a console application to test the OData service](#create-a-console-application-to-test-the-odata-service)
7 | - [Create a custom entity and implement the query implementation class](#create-a-custom-entity-and-implement-the-query-implementation-class)
8 | - [Create a custom entity](#create-a-custom-entity)
9 | - [Implement the query implemenation class](#implement-the-query-implemenation-class)
10 | - [Add the custom entity as a value help](#add-the-custom-entity-as-a-value-help)
11 | - [Test the service](#test-the-service)
12 | - [Summary](#summary)
13 | - [Solution](sources)
14 |
15 |
16 | When creating a new entry with your inventory application you see that there is no value help for the field **ProductId**.
17 | Since this information resides in a SAP S/4 HANA backend we will it retrieve via OData.
18 |
19 | 
20 |
21 | In this exercise you will thus learn how to consume an OData Service from an on premise system in order to fetch business partner data. You will then learn how to expose this data as a value help for the Inventory entity.
22 |
23 | In this exercise, we will ...
24 |
25 | - Create a Service Consumption Model for the on premise OData Service
26 | - Create a console application to test the OData Service call
27 | - Create a Custom Entity and implement its custom query
28 | - Expose your Custom Entity within your existing OData Service
29 | - Add the Custom Entity as a value help for the field ProductId in your inventory application
30 |
31 |
32 | > **Please note:**
33 |
34 | > Since it must be possible to run this demo on the trial systems where no destination service is available we cannot use RFC calls to retrieve data from a backend system. We have rather to use services that are publically available in the Internet. In our demo we will thus use an OData Service that is available in the SAP Gateway Demo System ES5 and that does not require any authentication.
35 |
36 |
37 |
38 | ## Create the Service Consumption Model
39 |
40 | In this step we will generate a so called **Service Consumption Model**. This type of object takes an external interface description as its input. Currently *OData*, *SOAP* and *RFC* are supported.
41 | Based on the information found in the *$metadata* file or the *wsdl* file appropriate repository objects are generated (OData Client proxy or SOAP proxy objects). For RFC function modules the metadata file is created in the backend using the transaction *ACO_PROXY*.
42 | Using these objects you will be able to write ABAP code that lets you consume remote OData services, SOAP services or RFC function modules.
43 |
44 | We start by creating a service consumption model for an OData service that provides demo product data. This service resides on the public SAP Gateway System ES5 and does not require any authentication
45 |
46 | 1. The *$metadata* file of the OData service that we want to consume must be uploaded in file format. You have hence to download it first.
47 |
48 | - Click on the following URL https://sapes5.sapdevcenter.com/sap/opu/odata/sap/ZPDCDS_SRV/$metadata
49 |
50 | When you are asked to select a certificate or to authenticate, simply press the **Cancel** button, since this URL does not require any authentication.
51 |
52 | 
53 |
54 | - Download the $metadata file to your computer, you will need it later in this exercise.
55 |
56 | 
57 | 
58 |
59 | 2. Switch to ADT and right click on your package **ZRAP_INVENTORY_####**. Select **New > Other ABAP Repository Object**.
60 |
61 | 
62 |
63 | 2. In the New ABAP Repository Object dialogue do the following
64 |
65 | - Start to type **`Service`**
66 | - In the list of objects select **Service Consumption Model**
67 | - Click **Next**
68 |
69 | 
70 |
71 | 4. The **New Service Consumption Model** dialogue opens. Here enter the following data:
72 |
73 | - Name: **`ZSC_RAP_PRODUCTS_#### `**
74 | - Description: **`Products from ES5`**
75 | - Remote Consumption Model: **`OData`** (to be selected from the drop down box)
76 |
77 |
78 | > **Caution**
79 |
80 | > Be sure that you have selected **`OData`** as the **Remote Consumption Mode** from the drop down box. We will create a service consumption model for a SOAP web service in the following exercise.
81 |
82 | 
83 |
84 | 5. The $metadata file of the OData service that we want to consume must be uploaded in file format. If you have not yet downloaded the $metadata file you have to do this now.
85 |
86 | - Click **Browse** to select the $metadata file that you have downloaded earlier in this exercise
87 | - Prefix: **`RAP_####_`**
88 |
89 | > **Please note**
90 |
91 | > The prefix that you have entered will be added to the names of the repository objects that are generated, namely the **abstract entity(ies)**.
92 | > If you don't select a prefix and if the wizard finds out that there would be name clashes the wizard will propse unique names by adding arbitrary characters to the repository object names. In any case you will be able to change the values that will be proposed by this wizard.
93 |
94 | 
95 |
96 | 6. Check the **ABAP Artifact Name** and click **Next**.
97 |
98 | You will notice that the name of the ABAP artifact has been set to `ZRAP_####_SEPMRA_I_PRODUCT_E` since we have provided the prefix `RAP_####_`.
99 |
100 | Press **Next**.
101 |
102 | > Additional Information
103 |
104 | > If you have not provided a prefix the ABAP Artifact Name might contain several arbritray characters that have been added to the name **ZSEPMRA_I_PRODUCT**. This can happen if other users in the same system have already imported the same $metadata file. In order to avoid name clashes the wizard then adds arbitrary characters so that a unique name for the ABAP artifact is ensured.
105 |
106 | 
107 |
108 | 7. The wizard will now list the repository objects that will be generated, namely a service definition and an abstract entity in addition to the service consumption model.
109 |
110 | - Service Definition: **ZSC_RAP_PRODUCTS_####**
111 | - Abstract Entity: **ZRAP_####_SEPMRA_I_PRODUCT_E**
112 |
113 | Click **Next**.
114 |
115 | 
116 |
117 | 8. Selection of transport request
118 | - Select or create a transport request
119 | - Press **Finish**
120 |
121 | 
122 |
123 | 9. Let us briefly investigate the service consumption model.
124 |
125 | For each operation (**Read List**, **Read**, **Create**, **Update** and **Delete**) some sample code has been created that you can use when you want to call the OData Service with one of these operations. Since we want to retrieve a list of Product-IDs, we will select the operation **Read List** and click on the button **Copy to Clipboard**. We will use this code in the following step where we create a console application to test the call to the remote OData service.
126 |
127 | 
128 |
129 | ## Remove dimension fields from abstract entity
130 |
131 | In order to avoid an error when the custom entity is used as a value help we have to remove the dimension fields from the abstract entity. Otherwise a convesion error occurs that will lead to a dump. The root cause is being analyzed but was not solved before our session took place.
132 |
133 | 1. Remove dimensions from the abstract entity
134 |
135 | Please open the entity **`ZRAP_####_SEPMRA_I_PRODUCT_E`** (Press **Ctrl+Shift+A**) and paste the name (of course with your number `####`) and comment out following part:
136 |
137 |
138 | // @OData.property.valueControl: 'Height_vc'
139 | // @Semantics.quantity.unitOfMeasure: 'DimensionUnit'
140 | // Height : abap.dec( 13, 3 ) ;
141 | // Height_vc : rap_cp_odata_value_control ;
142 | // @OData.property.valueControl: 'Width_vc'
143 | // @Semantics.quantity.unitOfMeasure: 'DimensionUnit'
144 | // Width : abap.dec( 13, 3 ) ;
145 | // Width_vc : rap_cp_odata_value_control ;
146 | // @OData.property.valueControl: 'Depth_vc'
147 | // @Semantics.quantity.unitOfMeasure: 'DimensionUnit'
148 | // Depth : abap.dec( 13, 3 ) ;
149 | // Depth_vc : rap_cp_odata_value_control ;
150 |
151 |
152 | 
153 |
154 | 2. Afterwards please activate  your changes.
155 |
156 | ## Create a console application to test the OData service
157 |
158 | We can now test the service consumption model by creating a small console application **ZCL_CE_RAP_PRODUCTS_####** that implements the interface **if_oo_adt_classrun**.
159 | This is a useful additional step since this way it is easier to check whether the OData consumption works and debugging a console application is much easier than trying out your coding in the full fledged RAP business object.
160 |
161 | > **Please note**
162 |
163 | > We will use this class at a later stage also as an implementation for our custom query and we hence choose a name **ZCL_CE_RAP_PRODUCTS_####** that already contains the name of the to be created custom entity. **CE** denotes that this class will act as a query implementation for a *Custom Entity*.
164 |
165 | 1. Right click on the folder **Source Code Library** and select **New > ABAP Class**.
166 |
167 | 
168 |
169 | 2. The **New ABAP class** dialogue opens. Here you have to enter the following:
170 |
171 | - Name: **`ZCL_CE_RAP_PRODUCTS_####`**
172 | - Description: **`Query implementation custom entity`**
173 | - Click **Add**
174 |
175 | The **Add ABAP Interface** dialogue opens.
176 |
177 | - Start to type **`if_oo`**
178 | - Select **`IF_OO_ADT_CLASSRUN`** from the list of matching items
179 | - Press **OK** or double-click on **IF_OO_ADT_CLASSRUN**
180 |
181 | 
182 |
183 |
184 | 3. Check the input and press **Next**
185 |
186 | 
187 |
188 | 4. Selection of transport request
189 |
190 | - Select or create a transport request
191 | - Click **Finish**
192 |
193 | 
194 | ZRAP_CE
195 |
196 | 5. Check the source code template
197 |
198 | You will notice that the wizard has automatically added an implementation for the method **IF_OO_ADT_CLASSRUN~MAIN**.
199 |
200 | 
201 |
202 | ## CLASS zcl_ce_rap_products_#### - Implementation
203 |
204 | 1. Let's start with the implementation of our test class.
205 |
206 | In the public section we add two **TYPES** definitions. **t_product_range** is used to provide filter conditions for ProductIDs in form of SELECT-OPTIONS to the method **get_products( )**.
207 | The second type **t_business_data** is used to retrieve the business data returned by our remote OData service.
208 | The **get_products( )** method takes filter conditions in form of SELECT-OPTIONS via the importing parameter **it_filter_cond**. In addition it is possible to provide values for **top** and **skip** to leverage client side paging.
209 |
210 | So the **DEFINITION** section of your class should now look like follows:
211 |
212 |
213 | CLASS zcl_ce_rap_products_#### DEFINITION
214 | PUBLIC
215 | FINAL
216 | CREATE PUBLIC .
217 |
218 | PUBLIC SECTION.
219 |
220 | INTERFACES if_oo_adt_classrun .
221 |
222 | TYPES t_product_range TYPE RANGE OF zrap_####_sepmra_i_product_e-product.
223 | TYPES t_business_data TYPE TABLE OF zrap_####_sepmra_i_product_e.
224 |
225 | METHODS get_products
226 | IMPORTING
227 | it_filter_cond TYPE if_rap_query_filter=>tt_name_range_pairs OPTIONAL
228 | top TYPE i OPTIONAL
229 | skip TYPE i OPTIONAL
230 | EXPORTING
231 | et_business_data TYPE t_business_data
232 | RAISING
233 | /iwbep/cx_cp_remote
234 | /iwbep/cx_gateway
235 | cx_web_http_client_error
236 | cx_http_dest_provider_error
237 | .
238 |
239 | PROTECTED SECTION.
240 | PRIVATE SECTION.
241 | ENDCLASS.
242 |
243 |
244 | You will get a warning that the method **get_products( )** has not been implemented yet. Press **Ctrl+1** to start the quick fix to add an implementation for **get_products( )**.
245 |
246 | 
247 |
248 | 6. Now we will add code in the **IMPLEMENTATION** section of the method **get_products( )**.
249 |
250 | The public method **get_products( )** is used to retrieve the data from the remote OData service. Since it is not possible to leverage the destination service in the trial systems, we will use the method **cl_http_destination_provider=>create_by_url** which allows us to create a http destination object based on the target URL. As the target URL we choose the root URL https://sapes5.sapdevcenter.com of the ES5 system since the relative URL that points to the OData service will be added when creating the OData client proxy.
251 |
252 | > **Caution:**
253 | > Do not forget to replace the placeholder **'####'** with your unique number.
254 |
255 | > Please note
256 |
257 | > In a normal SAP Cloud Platform, ABAP Environment system one would leverage the destination service of the underlying Cloud Foundry Environment and one would use the statement **cl_http_destination_provider=>create_by_cloud_destination** to generate a http destination in the ABAP Environment system based on these settings.
258 |
259 | 
260 |
261 |
262 | METHOD get_products.
263 |
264 | DATA: filter_factory TYPE REF TO /iwbep/if_cp_filter_factory,
265 | filter_node TYPE REF TO /iwbep/if_cp_filter_node,
266 | root_filter_node TYPE REF TO /iwbep/if_cp_filter_node.
267 |
268 | DATA: http_client TYPE REF TO if_web_http_client,
269 | odata_client_proxy TYPE REF TO /iwbep/if_cp_client_proxy,
270 | read_list_request TYPE REF TO /iwbep/if_cp_request_read_list,
271 | read_list_response TYPE REF TO /iwbep/if_cp_response_read_lst.
272 |
273 | DATA(http_destination) = cl_http_destination_provider=>create_by_url( i_url = 'https://sapes5.sapdevcenter.com' ).
274 | http_client = cl_web_http_client_manager=>create_by_http_destination( i_destination = http_destination ).
275 |
276 | odata_client_proxy = cl_web_odata_client_factory=>create_v2_remote_proxy(
277 | EXPORTING
278 | iv_service_definition_name = 'ZSC_RAP_PRODUCTS_####'
279 | io_http_client = http_client
280 | iv_relative_service_root = '/sap/opu/odata/sap/ZPDCDS_SRV/' ).
281 |
282 | " Navigate to the resource and create a request for the read operation
283 | read_list_request = odata_client_proxy->create_resource_for_entity_set( 'SEPMRA_I_PRODUCT_E' )->create_request_for_read( ).
284 |
285 | " Create the filter tree
286 | filter_factory = read_list_request->create_filter_factory( ).
287 | LOOP AT it_filter_cond INTO DATA(filter_condition).
288 | filter_node = filter_factory->create_by_range( iv_property_path = filter_condition-name
289 | it_range = filter_condition-range ).
290 | IF root_filter_node IS INITIAL.
291 | root_filter_node = filter_node.
292 | ELSE.
293 | root_filter_node = root_filter_node->and( filter_node ).
294 | ENDIF.
295 | ENDLOOP.
296 |
297 | IF root_filter_node IS NOT INITIAL.
298 | read_list_request->set_filter( root_filter_node ).
299 | ENDIF.
300 |
301 | IF top > 0 .
302 | read_list_request->set_top( top ).
303 | ENDIF.
304 |
305 | read_list_request->set_skip( skip ).
306 |
307 | " Execute the request and retrieve the business data
308 | read_list_response = read_list_request->execute( ).
309 | read_list_response->get_business_data( IMPORTING et_business_data = et_business_data ).
310 |
311 | ENDMETHOD.
312 |
313 |
314 | 8. Finally we add the following code into the **IMPLEMENTATION** section of your **main** method
315 |
316 | The main method creates a simple filter for products with a name greater or equal **HT-1200**. At the same time we use client side paging to skip the first result and limit the response to 3 products.
317 |
318 |
319 | METHOD if_oo_adt_classrun~main.
320 |
321 | DATA business_data TYPE TABLE OF zrap_####_sepmra_i_product_e.
322 | DATA filter_conditions TYPE if_rap_query_filter=>tt_name_range_pairs .
323 | DATA ranges_table TYPE if_rap_query_filter=>tt_range_option .
324 | ranges_table = VALUE #( ( sign = 'I' option = 'GE' low = 'HT-1200' ) ).
325 | filter_conditions = VALUE #( ( name = 'PRODUCT' range = ranges_table ) ).
326 |
327 | TRY.
328 | get_products(
329 | EXPORTING
330 | it_filter_cond = filter_conditions
331 | top = 3
332 | skip = 1
333 | IMPORTING
334 | et_business_data = business_data
335 | ) .
336 | out->write( business_data ).
337 | CATCH cx_root INTO DATA(exception).
338 | out->write( cl_message_helper=>get_latest_t100_exception( exception )->if_message~get_longtext( ) ).
339 | ENDTRY.
340 |
341 | ENDMETHOD.
342 |
343 |
344 |
345 | 9. The code should now look as follows
346 |
347 | [Source code zcl_ce_rap_products_####](sources/ex2_CLAS_zcl_ce_rap_products_%23%23%23%23_step_1.txt)
348 |
349 | 10. You can now run the console application by pressing **F9**.
350 |
351 |
352 | 
353 |
354 |
355 | ## Create a custom entity and implement the query implementation class
356 |
357 | Since we want to use the results of the remote OData service in our managed inventory app we will create a custom entity.
358 | The syntax of a custom entity differs from the one used in normal CDS views but is very similar to the syntax of an abstract entity and we can thus reuse most of the DDL source code of the abstract entity that has been generated when the service consumption model was created.
359 |
360 | In order to leverage the remote OData service in our application we have to perform two steps.
361 |
362 | 1. We have to create a custom entity.
363 | 2. We have to create a class that implements the query for the custom entity. (Here we will reuse the class that we have created earlier and that we have used to test the remote OData service).
364 |
365 | ### Create a custom entity
366 |
367 | In constrast to "normal" CDS views that read data from the database from tables or other CDS views the so called custom entities act as a wrapper for a code based implementation that provides the data instead of a database table or a CDS view.
368 |
369 | The custom entity has to be created manually and it uses a similar syntax as the abstract entity that has been created when we have created our service consumption model.
370 |
371 | In order to be able to retrieve the data from the remote OData service we have to built a class that implements the interface **if_rap_query_provider**. We will reuse the class that we have created earlier and add this interface to it.
372 |
373 | The interface **if_rap_query_provider interface** only offers one method which is called **select**. Within this select method we will call the public **get_products( )** method. The select method also expects that the incoming requests provide certain OData specific query parameters. These we will set in our coding as well.
374 |
375 | 1. Right-click on the folder **Data Definition** and select **New Data Definition.**
376 |
377 | 
378 |
379 |
380 | 1. Let’s start with creating a new data definition `ZCE_RAP_PRODUCTS_####` using the template for a custom entity.
381 |
382 | 2. The **New Data Defintion** dialogue opens
383 | - Name: **`ZCE_RAP_PRODUCTS_####`**
384 | - Description: **`Custom entity for products from ES5`**
385 |
386 | Press **Next**
387 |
388 | 
389 |
390 | 3. Selection of a transport request
391 | - Select or create a transport request.
392 | - **!!! ONLY !!!** Press *Next*. Do **NOT** press *Finish*.
393 |
394 | > Caution
395 |
396 | > If you were to press **Finish** instead of **Next**, the wizard would use the template that was used the last time when this wizard was used by the developer.
397 |
398 | > In order to be sure that the correct template is selected, we **MUST** press **Next** and not **Finish** which would skip the step of template selection.
399 |
400 | 
401 |
402 | 4. Select Template
403 |
404 | - Use the scroll bar to navigate down the list
405 | - Select the template **Define custom entity with parameters**
406 | - Press **Finish**
407 |
408 | > **Please note**
409 |
410 | > There is only a template for a custom entity with parameters. But this doesn’t matter. We use this template and remove the statement `with parameters parameter_name : parameter_type`.
411 |
412 | 
413 |
414 | 5. Edit the source code of the custom entity
415 |
416 | - Remove the statement with parameters parameter_name : parameter_type
417 |
418 | 
419 |
420 | - Copy the field list from the abstract entity `ZRAP_####_SEPMRA_I_PRODUCT_E`
421 |
422 | 
423 |
424 |
425 | - and paste it between the curly brackets as the new field list of our custom entity.
426 |
427 | 
428 |
429 | 6. Now add the annoation `@ObjectModel.query.implementedBy: 'ABAP:ZCL_CE_RAP_PRODUCTS_####'`
430 |
431 | 
432 |
433 | 7. Activate your changes 
434 |
435 | 
436 |
437 | 9. The DDL source code should now look like follows
438 |
439 | [Source code ZCE_RAP_PRODUCTS_####](sources/ex2_DDLS_ZCE_RAP_PRODUCTS_%23%23%23%23.txt)
440 |
441 | **Please note: You have to adapt the number of decimals for the property Price**
442 |
443 | 10. Change the number of decimals for the property `Price`.
444 |
445 | Change the number of decimals for the property `Price` from **3** to **2**, so that it now reads as follows:
446 | Price : abap.curr( 16, 2 );
447 |
448 | 
449 |
450 | ### Implement the query implemenation class
451 |
452 | After having created the custom entity `ZRAP_CE_PRODUCTS_####` we now have to enhance the query implementation class `ZCL_CE_RAP_PRODUCTS_####`that we have created earlier in this exercise.
453 |
454 |
455 | 1. Add interface **`IF_RAP_QUERY_PROVIDER`** to the query implementation class **ZCL_CE_RAP_PRODUCTS_####**
456 |
457 | - You can use the quick fix `Ctrl+1` to add the implementation for the method `if_rap_query_provider~select`
458 |
459 |
460 | INTERFACES if_rap_query_provider.
461 |
462 |
463 | 
464 |
465 |
466 |
467 | 2. Implement the method `if_rap_query_provider~select`
468 |
469 | Within the `select()` method we can retrieve the details of the incoming OData call using the object `io_request`. Using the method `get_paging()` we can find out whether client side paging was requested with the incoming OData call. Using the method `get_filter()` we can retrieve the filter that was used by the incoming OData request as ranges. This comes in handy so we can provide this data when calling the method `get_products()`.
470 |
471 | **Please note:**
472 | It is mandatory that the response not only contains the retrieved data via the method `set_data()` but also the number of entities being returned via the method `set_total_number_of_records()`.
473 |
474 |
475 |
476 | METHOD if_rap_query_provider~select.
477 | DATA business_data TYPE TABLE OF zrap_####_sepmra_i_product_e.
478 | DATA(top) = io_request->get_paging( )->get_page_size( ).
479 | DATA(skip) = io_request->get_paging( )->get_offset( ).
480 | DATA(requested_fields) = io_request->get_requested_elements( ).
481 | DATA(sort_order) = io_request->get_sort_elements( ).
482 |
483 | TRY.
484 | DATA(filter_condition) = io_request->get_filter( )->get_as_ranges( ).
485 |
486 | get_products(
487 | EXPORTING
488 | it_filter_cond = filter_condition
489 | top = CONV i( top )
490 | skip = CONV i( skip )
491 | IMPORTING
492 | et_business_data = business_data
493 | ) .
494 |
495 | io_response->set_total_number_of_records( lines( business_data ) ).
496 | io_response->set_data( business_data ).
497 |
498 | CATCH cx_root INTO DATA(exception).
499 | DATA(exception_message) = cl_message_helper=>get_latest_t100_exception( exception )->if_message~get_longtext( ).
500 | ENDTRY.
501 | ENDMETHOD.
502 |
503 |
504 |
505 |
506 | 3. Activate your changes
507 |
508 | 4. Your ABAP source code should now look like follows
509 |
510 | [Source code ZCL_CE_RAP_PRODUCTS_####](sources/ex2_CLAS_zcl_ce_rap_products_%23%23%23%23_final.txt)
511 |
512 | ## Add the custom entity to your service definition
513 |
514 | 1. Open the Service Definition `ZRAP_INVENTORY_####`
515 |
516 | - add the statement
517 | expose ZCE_RAP_PRODUCTS_#### as Products;
518 | so that the custom entity is added to the OData service.
519 | - Activate your changes 
520 |
521 | 
522 |
523 | ## Add the custom entity as a value help
524 |
525 | 1. Open the projection view for your inventory data `ZC_RAP_INVENTORY_####`
526 |
527 | - Add the annotation `@Consumption.valueHelpDefinition` to the field `ProductID`
528 |
529 |
530 | @Consumption.valueHelpDefinition: [{ entity : {name: 'ZCE_RAP_PRODUCTS_####', element: 'Product' } }]
531 | ProductID,
532 |
533 |
534 | This will add the custom entity `ZCE_RAP_PRODUCTS_####` as a value help for the field `ProductId`.
535 |
536 |
537 | ## Test the service
538 |
539 | 1. Open the service binding `ZUI_RAP_INVENTORY_####_02`
540 |
541 | - You will notice that now two entities are visible. `Products` and `Inventory`
542 |
543 | 
544 |
545 | > Caution:
546 | > At this point you might receive an error message such as
547 | > **Amount field PRICE with currency decimals not equal to two is not supported.**
548 | > If this is the case go back to your custom entity **ZCE_RAP_PRODUCTS_####**
549 | > And change the number of decimals for the property price from 3 to 2, so that it now reads as follows:
550 | > Price : abap.curr( 16, 2 );
551 |
552 | 
553 |
554 |
555 | 2. Start the Fiori Elements preview
556 |
557 | - Create a new inventory
558 | - Click on the value help icon
559 |
560 | 
561 |
562 |
563 | 3. The search results are on the buttom of the window. So you have to scroll down using the scroll bar on the right hand side.
564 |
565 | 
566 |
567 | 4. Select a product e.g. HT-1000
568 |
569 | 
570 |
571 |
572 | 5. Check the result on the object page
573 |
574 | 
575 |
576 |
577 | ## Summary
578 |
579 | You are now able to:
580 | · Explore an existing application with the Fiori Elements preview
581 | · Consume external OData Service using the Service Consumption Model
582 | · Create and expose Custom Entites
583 | · Implement Custom Queries for Custom Entities
584 | · Define value helps for OData entities
585 |
586 |
587 | Continue to - [Exercise 3 - Excercise 3 ](../ex3/README.md)
588 |
--------------------------------------------------------------------------------