-
Notifications
You must be signed in to change notification settings - Fork 286
/
zcl_demo_abap_rap_m_as.clas.abap
289 lines (257 loc) · 12.7 KB
/
zcl_demo_abap_rap_m_as.clas.abap
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
"! <p class="shorttext"><strong>Local consumption of RAP Business Events</strong><br/>ABAP cheat sheet example class</p>
"!
"! <p>The example class demonstrates local consumption of RAP business events in the context of a RAP demo
"! scenario (managed RAP BO with managed internal numbering and additional save).
"! The class represents a RAP BO consumer.<br/> Choose F9 in ADT to run the class.</p>
"!
"! <h2>Note</h2>
"! <ul><li>Primarily, the example demonstrates the local consumption of RAP
"! business events.</li>
"! <li>For that purpose, the BDEF defines three events. Two of them are
"! specified with a parameter. The events are raised for create, update
"! and delete operations.</li>
"! <li>The example implementation in this class (the RAP BO consumer)
"! contains three ABAP EML modify requests: a RAP create, update and
"! delete operation. For each of the operations, an event is raised
"! using a RAISE ENTITY EVENT statement. The events are raised in the
"! save_modified RAP saver method in the CCIMP include of the behavior
"! pool.</li>
"! <li>When the events are raised, the RAP event handler methods are called
"! asynchronously. To demonstrate the effect of the events, a database
"! table representing a log table is populated.</li>
"! <li>In the output of the example, the content of internal tables is
"! displayed to demonstrate the effect of the RAP operations by
"! selecting from the database table where the RAP BO instances are
"! persisted to after each RAP operation. Additionally, the content
"! of an internal table is displayed including the entries that have been
"! inserted into the log database table by the event handler methods.
"! In this self-contained example, this 'log database table' is just a
"! database table that is used to store some entries triggered by the RAP
"! events for visualization purposes. You can imagine that, for example,
"! the sending of an email is triggered there, or the application log is
"! filled, and so on. The log table is used in another RAP example as
"! draft table. The draft concept is not relevant for this simplified
"! example here.</li>
"! <li>Note the comments in the example code. You can check out the
"! asynchronity by commenting out the WAIT statement further down.</li>
"! <li> This simplified example is not a real life scenario and rather
"! focuses on the technical side by giving an idea how the communication
"! and data exchange between a RAP BO consumer, which is a class
"! in this case, and RAP BO provider can work. Additionally, it shows
"! how the methods for non-standard RAP BO operations might be
"! self-implemented in an ABP. The example is intentionally kept
"! short and simple and focuses on specific RAP aspects. For this reason,
"! the example might not fully meet the requirements of the RAP BO contract.</li>
"! <li>Find information on <strong>getting started with the example class</strong> and the
"! <strong>disclaimer</strong> in the ABAP Doc comment of class {@link zcl_demo_abap_aux}.</li>
"! </ul>
"!
"! <h2>Related artifacts</h2>
"! <ul><li>RAP BO consumer: {@link zcl_demo_abap_rap_m_as} (this class here)</li>
"! <li>RAP BO provider (ABAP behavior pool): {@link zbp_demo_abap_rap_ro_m_as}</li>
"! <li>RAP event handler: {@link zcl_demo_abap_rap_evt_handler}</li>
"! <li>BDEF: {@link zdemo_abap_rap_ro_m_as}</li>
"! <li>More artifacts are related such as database tables, CDS views, and
"! an abstract entity ({@link zdemo_abap_abstract_ent}; used for the parameter
"! specifications for the events in the BDEF)</li>
"! </ul>
CLASS zcl_demo_abap_rap_m_as DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES: if_oo_adt_classrun.
CLASS-METHODS:
class_constructor.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap_rap_m_as IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
out->write( |ABAP Cheat Sheet Example: Local Consumption of RAP Business Events\n\n| ).
"RAP create operation that creates multiple calculations
"Note the AUTO FILL CID addition with which the required %cid values
"for RAP BO instances are created automatically. Since the scenario is
"managed internal numbering, the 'id' field is assigned an appropriate value
"automatically by the RAP framework.
MODIFY ENTITY zdemo_abap_rap_ro_m_as
CREATE AUTO FILL CID
FIELDS ( num1 arithm_op num2 )
WITH VALUE #( ( num1 = 1
arithm_op = '+'
num2 = 2 )
( num1 = 5
arithm_op = '-'
num2 = 30 )
( num1 = 3
arithm_op = '*'
num2 = 3 )
( num1 = 7
arithm_op = '/'
num2 = 5 )
( num1 = 2
arithm_op = 'P'
num2 = 4 )
( num1 = 10
arithm_op = 'P'
num2 = 1000000000 )
( num1 = 2
arithm_op = '/'
num2 = 0 ) )
MAPPED DATA(m_cr)
FAILED DATA(f_cr)
REPORTED DATA(r_cr).
COMMIT ENTITIES.
IF sy-subrc <> 0.
out->write( `An issue occurred in the RAP save sequence.` ).
ENDIF.
"Getting and displaying persisted instances to show the effect of the
"EML MODIFY statement
SELECT id, num1, arithm_op, num2, calc_result, crea_date_time, lchg_date_time
FROM zdemo_abap_tabca
ORDER BY lchg_date_time
INTO TABLE @DATA(dbtab_entries).
out->write( `Database table entries after the create operation`
)->write( dbtab_entries
)->write( |\n| ).
**********************************************************************
"RAP update operation
"In the example, all RAP BO instances that were created above are
"updated. Here, the second number is updated with a random
"integer (from the value range 1 - 10). For this purpose, the
"cl_abap_random_int class is used.
"The reference to existing instances is made using entries in the
"mapped reponse table from above (it contains all keys of the created
"RAP BO instances).
IF m_cr-root IS NOT INITIAL.
MODIFY ENTITY zdemo_abap_rap_ro_m_as
UPDATE FIELDS ( num2 )
WITH VALUE #( FOR wa IN m_cr-root ( id = wa-id
num2 = cl_abap_random_int=>create(
seed = cl_abap_random=>seed( )
min = 1
max = 10 )->get_next( ) ) )
FAILED DATA(f_upd)
REPORTED DATA(r_upd).
COMMIT ENTITIES.
IF sy-subrc <> 0.
out->write( `An issue occurred in the RAP save sequence.` ).
ENDIF.
"Getting and displaying persisted instances to show the effect of the
"EML MODIFY statement
SELECT id, num1, arithm_op, num2, calc_result, crea_date_time, lchg_date_time
FROM zdemo_abap_tabca
ORDER BY lchg_date_time
INTO TABLE @dbtab_entries.
out->write( `Database table entries after the update operation`
)->write( dbtab_entries
)->write( |\n| ).
ENDIF.
**********************************************************************
"RAP delete operation
"As above, the reference to existing RAP BO instances is made
"using entries in the mapped response table. In the example,
"the first three instances created are deleted.
IF lines( m_cr-root ) > 3.
MODIFY ENTITY zdemo_abap_rap_ro_m_as
DELETE FROM VALUE #( ( id = m_cr-root[ 1 ]-id )
( id = m_cr-root[ 2 ]-id )
( id = m_cr-root[ 3 ]-id ) )
FAILED DATA(f_del)
REPORTED DATA(r_del).
COMMIT ENTITIES.
IF sy-subrc <> 0.
out->write( `An issue occurred in the RAP save sequence.` ).
ENDIF.
"Getting and displaying persisted instances to show the effect of the
"EML MODIFY statement
SELECT id, num1, arithm_op, num2, calc_result, crea_date_time, lchg_date_time
FROM zdemo_abap_tabca
ORDER BY lchg_date_time
INTO TABLE @dbtab_entries.
out->write( `Database table entries after the delete operation`
)->write( dbtab_entries
)->write( |\n| ).
ENDIF.
**********************************************************************
"Note:
"- Due to the asynchronous call of the events, a WAIT statement
" is included to give the events some time in this self-contained example,
" i.e. so that all the database table entries that are created in the
" RAP event handler method can be retrieved and displayed.
"- In the RAP event handler method implementation, note the cl_abap_tx=>save( ).
" method call. This explicit activation of the 'save' transactional phase
" is required because, when called, the methods are started in the
" 'modify' transactional phase. In the modify phase, database modification
" statements are not allowed. If the save phase is not activated,
" a following database modification statement results in an error.
"To explore the asynchronity of the event raising, you can comment out the
"following WAIT statement.
WAIT UP TO 2 SECONDS.
DATA(tmstmp_after_wait) = cl_abap_tstmp=>utclong2tstmp( utclong_current( ) ).
out->write( |Timestamp (e.g. for comparing with the timestamps of the events raised): { tmstmp_after_wait }| ).
out->write( |\n| ).
"The global class of the behavior pool contains a static attribute of type i.
"The example is implemented as follows: When events are raised in the save_modified
"method, this number is increased by 1 per event raised. The number represents
"the expected events to be raised. It is used in the following example implementation.
"As mentioned above, you can comment out the WAIT statement to potentially see
"a different number here compared to the number of entries in the log table.
out->write( |Number of expected events raised: { zbp_demo_abap_rap_ro_m_as=>num_raised_events }| ).
out->write( |\n| ).
"Getting and displaying database table entries that were inserted
"in the event handler method implementations to demonstrate that
"events have been triggered.
SELECT calc_result, crea_date_time
FROM zdemo_abap_draft
ORDER BY crea_date_time
INTO TABLE @DATA(evt_log_entries).
out->write( |Entries in log table at this stage (after SELECT from database table): { lines( evt_log_entries ) }| ).
out->write( |\n| ).
DATA(flag) = abap_false.
IF evt_log_entries IS INITIAL.
out->write( `There are no entries in the log table.` &&
` Try and run the example again.` ).
flag = abap_true.
ELSEIF lines( evt_log_entries ) BETWEEN 1 AND zbp_demo_abap_rap_ro_m_as=>num_raised_events - 1.
out->write( `Log database table entries created by the ` &&
`raised events` )->write( `Note that not all expected log database table entries have been created yet by the ` &&
`raised events`
)->write( evt_log_entries ).
flag = abap_true.
ELSE.
out->write( `Log database table entries created by the ` &&
`raised events`
)->write( evt_log_entries ).
ENDIF.
"The following implementation is included for exploring the asynchronity in the self-contained example, if you
"have commented out the WAIT statement above, or if not all expected entries are available in the database table
"yet. This is just to give it some more time and select from the database table again.
IF flag = abap_true.
out->write( |\n| ).
out->write( |******************************************************| ).
out->write( |\n| ).
out->write( |Out of { zbp_demo_abap_rap_ro_m_as=>num_raised_events } events that are expected to be raised in the example implementation, | &&
|only { lines( evt_log_entries ) } events are available in the database table at this stage. So, waiting a bit more ...| ).
out->write( |\n| ).
WAIT UP TO 1 SECONDS.
SELECT calc_result, crea_date_time
FROM zdemo_abap_draft
ORDER BY crea_date_time
INTO TABLE @evt_log_entries.
IF lines( evt_log_entries ) = zbp_demo_abap_rap_ro_m_as=>num_raised_events.
out->write( `Log database table entries created by the ` &&
`raised events after waiting some more time`
)->write( evt_log_entries ).
ELSE.
out->write( |Hmm... still not all events are available in the database table.| ).
out->write( evt_log_entries ).
ENDIF.
ENDIF.
ENDMETHOD.
METHOD class_constructor.
DELETE FROM zdemo_abap_tabca.
DELETE FROM zdemo_abap_draft.
CLEAR zbp_demo_abap_rap_ro_m_as=>num_raised_events.
ENDMETHOD.
ENDCLASS.