-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUpdateEntity.abap
More file actions
208 lines (177 loc) · 9.58 KB
/
Copy pathUpdateEntity.abap
File metadata and controls
208 lines (177 loc) · 9.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
*&---------------------------------------------------------------------
*& UPDATE_ENTITY - PUT / MERGE on a single entity
*&---------------------------------------------------------------------
*& REFERENCE COOKBOOK - READ BEFORE COPYING
*&
*& This file contains INDEPENDENT reference method bodies. They are NOT
*& meant to be pasted together into one DPC_EXT class. Types and function
*& module names are placeholders for your own generated artefacts.
*&
*& AUTHORIZATION BOUNDARY
*& Gateway authenticates the caller and checks service access; it does not
*& authorize the business operation. Production code must enforce the
*& application's own authorization before writing - here, or verifiably
*& inside the called function module. No authorization object is invented
*& in this repository.
*&
*& SCOPE: STANDALONE REQUEST / RFC TRANSACTION PATTERN
*& Example 2 demonstrates a STANDALONE (non-$batch) request that calls a
*& remote-enabled function module and owns the commit decision itself.
*&
*& It is NOT universally applicable. Inside a multi-operation $batch
*& CHANGESET the transaction boundary belongs to the Gateway changeset
*& processing, not to the individual CRUD method - see the note at the
*& commit and the root README, "Transaction Handling (SAP LUW)".
*&
*& TRANSACTION (SAP LUW) - standalone case
*& Validate the business return table BEFORE committing.
*&---------------------------------------------------------------------
" ---------------------------------------------------------------------
" Example 1 - SKELETON ONLY.
" Shows how to read the request payload and how to return messages.
" It performs NO write and therefore owns no transaction. Add your own
" persistence plus the commit rule from example 2 before using it.
" ---------------------------------------------------------------------
METHOD xxx_update_entity.
DATA ls_data LIKE er_entity. " er_entity is a STRUCTURE here
DATA lt_return TYPE bapiret2_t.
DATA(lo_message_container) = mo_context->get_message_container( ).
" Read the request payload.
TRY.
io_data_provider->read_entry_data( IMPORTING es_data = ls_data ).
CATCH /iwbep/cx_mgw_tech_exception INTO DATA(lx_tech).
lo_message_container->add_message_text_only( iv_msg_type = 'E'
iv_msg_text = 'Request payload could not be read' ).
RAISE EXCEPTION NEW /iwbep/cx_mgw_busi_exception(
message_container = lo_message_container
previous = lx_tech ).
ENDTRY.
" Keys arrive separately from the payload and carry the conversion exit
" already applied when read through get_converted_keys( ).
DATA ls_keys TYPE zcl_zsm_tst_mpc=>ts_keys.
io_tech_request_context->get_converted_keys( IMPORTING es_key_values = ls_keys ).
" <-- perform the actual update here, then apply the commit rule from
" example 2. Nothing is written in this skeleton.
" Echo the updated entity back to the client.
er_entity = ls_data.
" Success/info messages reach a Fiori client through the sap-message
" response header. Use a message class in productive code so the text
" is translatable - a hard-coded literal is not.
APPEND VALUE #( type = 'S' id = 'ZSM_M_01' number = '002' ) TO lt_return.
lo_message_container->add_messages_from_bapi( it_bapi_messages = lt_return
iv_add_to_response_header = abap_true ).
ENDMETHOD.
" ---------------------------------------------------------------------
" Example 2 - update through a remote-enabled function module, with the
" full local-vs-remote branch and the correct commit rule.
" ---------------------------------------------------------------------
METHOD xxx_update_entity.
CONSTANTS lc_rfc_name TYPE tfdir-funcname VALUE 'ZSM_FM_001'.
DATA ls_data TYPE zcl_zsm_tst_mpc=>ts_main.
DATA ls_keys TYPE zcl_zsm_tst_mpc=>ts_keys.
DATA lt_return TYPE bapiret2_t.
DATA lv_exc_msg TYPE string.
DATA lv_subrc TYPE sy-subrc.
DATA(lo_message_container) = mo_context->get_message_container( ).
" 1) Payload and keys.
TRY.
io_data_provider->read_entry_data( IMPORTING es_data = ls_data ).
CATCH /iwbep/cx_mgw_tech_exception INTO DATA(lx_tech).
lo_message_container->add_message_text_only( iv_msg_type = 'E'
iv_msg_text = 'Request payload could not be read' ).
RAISE EXCEPTION NEW /iwbep/cx_mgw_busi_exception(
message_container = lo_message_container
previous = lx_tech ).
ENDTRY.
io_tech_request_context->get_converted_keys( IMPORTING es_key_values = ls_keys ).
" ---------------------------------------------------------------
" 2) Resolve the destination from the SERVICE CONFIGURATION
" (system alias in /IWFND/MAINT_SERVICE) rather than from a
" hard-coded sy-sysid map. See DESTINATION/Destination.abap for
" why that matters.
" An initial/NONE destination means embedded deployment: hub and
" backend are the same system, so call locally.
" ---------------------------------------------------------------
DATA(lo_dp_facade) = /iwbep/if_mgw_conv_srv_runtime~get_dp_facade( ).
DATA(lv_destination) = /iwbep/cl_sb_gen_dpc_rt_util=>get_rfc_destination( io_dp_facade = lo_dp_facade ).
IF lv_destination IS INITIAL OR lv_destination = 'NONE'.
" Local call - shares the caller's LUW.
TRY.
CALL FUNCTION lc_rfc_name
EXPORTING is_data = ls_data
TABLES et_return = lt_return.
lv_subrc = sy-subrc.
CATCH cx_root INTO DATA(lx_root).
lv_subrc = 1001.
lv_exc_msg = lx_root->get_text( ).
ENDTRY.
ELSE.
" Remote call - runs in its OWN LUW on the target system.
CALL FUNCTION lc_rfc_name
DESTINATION lv_destination
EXPORTING is_data = ls_data
TABLES et_return = lt_return
EXCEPTIONS system_failure = 1000 MESSAGE lv_exc_msg
communication_failure = 1001 MESSAGE lv_exc_msg
OTHERS = 1002.
lv_subrc = sy-subrc.
ENDIF.
" ---------------------------------------------------------------
" 3) An RFC/communication failure is a TECHNICAL problem (5xx-class),
" not a business rejection. Do not flatten it into a business
" exception, and do not expose raw internal text to the client.
" ---------------------------------------------------------------
IF lv_subrc <> 0.
lo_message_container->add_message_text_only(
iv_msg_type = 'E'
iv_msg_text = 'The backend system could not be reached. Please contact support.' ).
" lv_exc_msg holds the RFC error text. Write it to your application
" log / the Gateway error log - never into the HTTP response, where
" it can disclose program, table and structure names.
RAISE EXCEPTION NEW /iwbep/cx_mgw_tech_exception(
message_container = lo_message_container ).
ENDIF.
" 4) Persist backend messages for support.
IF lt_return IS NOT INITIAL.
me->/iwbep/if_sb_dpc_comm_services~rfc_save_log( iv_entity_type = iv_entity_name
it_return = lt_return
it_key_tab = it_key_tab ).
ENDIF.
lo_message_container->add_messages_from_bapi( it_bapi_messages = lt_return
iv_add_to_response_header = abap_true ).
" ---------------------------------------------------------------
" 5) TRANSACTION DECISION.
" E / A / X mean the business operation failed -> raise, do NOT
" commit. Committing here would persist a failed update and return
" HTTP 204 as if it had worked.
" ---------------------------------------------------------------
IF line_exists( lt_return[ type = 'E' ] )
OR line_exists( lt_return[ type = 'A' ] )
OR line_exists( lt_return[ type = 'X' ] ).
RAISE EXCEPTION NEW /iwbep/cx_mgw_busi_exception(
message_container = lo_message_container ).
ENDIF.
" ---------------------------------------------------------------
" STANDALONE REQUEST ONLY - DO NOT COPY INTO CHANGESET PROCESSING
"
" Success path of a standalone (non-$batch) request, so this method
" owns the commit.
"
" A remote call runs in its own LUW on the target system, so the commit
" has to be issued THERE - hence iv_rfc_dest. A local call shares this
" LUW. That local-vs-remote distinction is the point of this example.
"
" This explicit commit is NOT suitable inside a multi-operation $batch
" changeset: a changeset is an atomic LUW, and committing per operation
" destroys that atomicity - a later failure in the same changeset can
" no longer undo what this operation already committed. Changeset
" transaction handling must be designed through the Gateway changeset
" lifecycle (CHANGESET_BEGIN / CHANGESET_END / CHANGESET_PROCESS)
" instead. See BATCH/README.md.
"
" commit_work( ) is the SEGW-generated DPC helper; its exact signature
" and behaviour are release-dependent - NEEDS OFFICIAL VERIFICATION for
" your SAP_GWFND release.
" ---------------------------------------------------------------
me->/iwbep/if_sb_dpc_comm_services~commit_work( iv_rfc_dest = lv_destination ).
ENDMETHOD.