├── .abapgit.xml
├── LICENSE
├── README.md
├── abaplint.json
├── docs
└── img
│ ├── UML Class Dia ABAP CAPI for HCM.png
│ ├── UML Class Dia.png
│ ├── UML Sequence Dia.png
│ ├── percent.png
│ ├── result HCM.png
│ └── result.png
├── logo
└── octo.svg
├── src
├── package.devc.xml
├── zcapi_facade
│ ├── package.devc.xml
│ └── zcapi_facade_hcm
│ │ ├── package.devc.xml
│ │ ├── zcapi_facade_hcm_example.prog.abap
│ │ ├── zcapi_facade_hcm_example.prog.xml
│ │ ├── zcapi_facade_hcm_example_cld.prog.abap
│ │ ├── zcapi_facade_hcm_example_cld.prog.xml
│ │ ├── zcapi_facade_hcm_example_cli.prog.abap
│ │ ├── zcapi_facade_hcm_example_cli.prog.xml
│ │ ├── zcl_capi_facade_hcm.clas.abap
│ │ ├── zcl_capi_facade_hcm.clas.xml
│ │ ├── zcl_capi_facade_hcm_abstr_cntx.clas.abap
│ │ ├── zcl_capi_facade_hcm_abstr_cntx.clas.xml
│ │ ├── zcl_capi_facade_hcm_abstr_task.clas.abap
│ │ ├── zcl_capi_facade_hcm_abstr_task.clas.xml
│ │ ├── zif_capi_facade_hcm_context.intf.abap
│ │ ├── zif_capi_facade_hcm_context.intf.xml
│ │ ├── zif_capi_facade_hcm_result.intf.abap
│ │ └── zif_capi_facade_hcm_result.intf.xml
├── zcl_capi_abstract_task.clas.abap
├── zcl_capi_abstract_task.clas.xml
├── zcl_capi_collection.clas.abap
├── zcl_capi_collection.clas.xml
├── zcl_capi_executors.clas.abap
├── zcl_capi_executors.clas.testclasses.abap
├── zcl_capi_executors.clas.xml
├── zcl_capi_iterator.clas.abap
├── zcl_capi_iterator.clas.xml
├── zcl_capi_message_handler.clas.abap
├── zcl_capi_message_handler.clas.xml
├── zcl_capi_spta_gateway.clas.abap
├── zcl_capi_spta_gateway.clas.xml
├── zcl_capi_thread_pool_executor.clas.abap
├── zcl_capi_thread_pool_executor.clas.testclasses.abap
├── zcl_capi_thread_pool_executor.clas.xml
├── zconcurrency_api.prog.abap
├── zconcurrency_api.prog.xml
├── zconcurrency_api.sots.0800272ae9a21edba8bedd438b158fed_e__0001.txt
├── zconcurrency_api.sots.0800272ae9a21edba8bf9e75f40d9082_e__0001.txt
├── zconcurrency_api.sots.xml
├── zconcurrency_api_example.prog.abap
├── zconcurrency_api_example.prog.xml
├── zconcurrency_api_example_cld.prog.abap
├── zconcurrency_api_example_cld.prog.xml
├── zconcurrency_api_example_cli.prog.abap
├── zconcurrency_api_example_cli.prog.xml
├── zcx_capi_tasks_invocation.clas.abap
├── zcx_capi_tasks_invocation.clas.xml
├── zif_capi_callable.intf.abap
├── zif_capi_callable.intf.xml
├── zif_capi_collection.intf.abap
├── zif_capi_collection.intf.xml
├── zif_capi_executor_service.intf.abap
├── zif_capi_executor_service.intf.xml
├── zif_capi_iterator.intf.abap
├── zif_capi_iterator.intf.xml
├── zif_capi_message_handler.intf.abap
├── zif_capi_message_handler.intf.xml
├── zif_capi_task.intf.abap
└── zif_capi_task.intf.xml
└── translations
└── ru
└── README.md
/.abapgit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | E
6 | /src/
7 | FULL
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021-2025 victorizbitskiy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | [](https://github.com/victorizbitskiy/zconcurrency_api/blob/main/LICENSE)
4 | 
5 | [](https://abaplint.app/stats/victorizbitskiy/zconcurrency_api)
6 |
7 | Translations:
8 | - [:ru: На русском языке](https://github.com/victorizbitskiy/zconcurrency_api/tree/main/translations/ru)
9 |
10 | ## `ABAP Concurrency API`
11 |
12 | API for parallel processing based on the SPTA Framework.
13 |
14 | `Note`: The initial idea was to make this API similar to the [Java Concurrency API](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/package-summary.html).
15 | Therefore, the name `ABAP Concurrency API` was chosen. However, in our case, calculations are performed not `concurrently` but `in parallel`.
16 | For more details please see [this](https://wiki.haskell.org/Parallelism_vs._Concurrency) explanation.
17 |
18 | ---
19 |
20 |
Don't forget to click ⭐ if you like the project!
21 |
22 | ---
23 |
24 | # Table of contents
25 | 1. [What it is?](#what-it-is)
26 | 2. [What is this for?](#what-is-this-for)
27 | 3. [Installation](#installation)
28 | 4. [Usage](#usage)
29 | 5. [Usage. HCM module](#using-in-the-HCM-module)
30 | 6. [Diagrams](#diagrams)
31 | 7. [Dependencies](#dependencies)
32 | 8. [Limitations](#limitations)
33 | 9. [How to contribute](#how-to-contribute)
34 | 10. [Got questions](#Got-questions)
35 | 11. [Logo](#logo)
36 |
37 | ## What it is?
38 |
39 | Utility classes useful in parallel programming.
40 |
41 | ## What is this for?
42 |
43 | Implementing parallel computing in ABAP typically involves the following steps:
44 |
45 | 1. Creating an RFC function module
46 | 2. **Implementation of business logic** inside it
47 | 3. Asynchronous calling RFC function module in a loop
48 | 4. Waiting for execution and **getting results of work**
49 |
50 | If you look at the resulting list, you will notice that, by and large, we are only interested in steps **`2`** and **`4`**.
51 | Everything else is routine work that takes time every time and, potentially, can be a source of errors.
52 |
53 | To avoid generating an RFC function module every time you need to do parallel processing, you can use the SPTA Framework provided by the vendor.
54 |
55 | The SPTA Framework is a good tool, but its interface leaves a lot to be desired. Because of this, the developer has to make a lot of effort to implement the parallelization process itself.
56 |
57 | In addition, writing clean code using the SPTA Framework directly is also not the easiest task. You need to be a real ninja to avoid using global variables. After all, the code can be confusing and difficult to maintain.
58 |
59 | The `ABAP Concurrency API` avoids these problems. With it, you can allow yourself to think more abstractly.
60 | You don't need to focus on parallelization. Instead, you can spend more time on the business logic of your application.
61 |
62 | ## Installation
63 |
64 | Installation is done with [abapGit](http://www.abapgit.org).
65 |
66 | ## Usage
67 |
68 | Let's consider a simple task:
69 |
70 | *You need to find the squares of numbers from **`1`** to **`10`***.
71 |
72 | The square of each of the numbers will be found in a separate task/process.
73 | The example is detached from the real world, but it is enough to understand how to work with the API.
74 |
75 | First, let's create the 3 local classes: *Context*, *Task* and *Result*.
76 | You can choose which classes to create (local or global).
77 |
78 | 1. **lcl_contex**, an object of this class encapsulates the task parameters.
79 | The use of this class is optional. You can do without it by passing the task parameters directly to its constructor.
80 | However, in my opinion, it is preferable to use a separate class.
81 |
82 |
83 | Show code...
84 |
85 | ```abap
86 | CLASS lcl_context DEFINITION FINAL.
87 | PUBLIC SECTION.
88 | INTERFACES if_serializable_object.
89 |
90 | TYPES:
91 | BEGIN OF ty_params,
92 | param TYPE i,
93 | END OF ty_params.
94 |
95 | METHODS:
96 | constructor IMPORTING is_params TYPE ty_params,
97 | get RETURNING VALUE(rs_params) TYPE ty_params.
98 |
99 | PRIVATE SECTION.
100 | DATA ms_params TYPE ty_params.
101 | ENDCLASS.
102 |
103 | CLASS lcl_context IMPLEMENTATION.
104 | METHOD constructor.
105 | ms_params = is_params.
106 | ENDMETHOD.
107 |
108 | METHOD get.
109 | rs_params = ms_params.
110 | ENDMETHOD.
111 | ENDCLASS.
112 | ```
113 |
114 |
115 | 2. **lcl_task**, describes an object *Task*. Contains business logic (in our case, raising a number to the power of 2).
116 | Note that the **lcl_task** class inherits from the **zcl_capi_abstract_task** class and overrides the **zif_capi_callable~call** method.
117 |
118 |
119 | Show code...
120 |
121 | ```abap
122 | CLASS lcl_task DEFINITION INHERITING FROM zcl_capi_abstract_task FINAL.
123 | PUBLIC SECTION.
124 |
125 | METHODS:
126 | constructor IMPORTING io_context TYPE REF TO lcl_context,
127 | zif_capi_callable~call REDEFINITION.
128 |
129 | PRIVATE SECTION.
130 | DATA mo_context TYPE REF TO lcl_context.
131 | DATA mv_res TYPE i.
132 | ENDCLASS.
133 |
134 | CLASS lcl_task IMPLEMENTATION.
135 | METHOD constructor.
136 | super->constructor( ).
137 | mo_context = io_context.
138 | ENDMETHOD.
139 |
140 | METHOD zif_capi_callable~call.
141 |
142 | DATA(ls_params) = mo_context->get( ).
143 | mv_res = ls_params-param ** 2.
144 |
145 | ro_result = new lcl_result( iv_param = ls_params-param
146 | iv_result = mv_res ).
147 | ENDMETHOD.
148 | ENDCLASS.
149 | ```
150 |
151 |
152 | 3. **lcl_result** describes *the result* of the task.
153 | This class must implement the **if_serializable_object** interface. Otherwise, you can describe it in any way you want.
154 |
155 |
156 |
157 | Show code...
158 |
159 | ```abap
160 | CLASS lcl_result DEFINITION FINAL.
161 | PUBLIC SECTION.
162 | INTERFACES if_serializable_object.
163 |
164 | METHODS:
165 | constructor IMPORTING iv_param TYPE i
166 | iv_result TYPE i,
167 | get RETURNING VALUE(rv_result) TYPE string.
168 |
169 | PRIVATE SECTION.
170 | DATA mv_param TYPE i.
171 | DATA mv_result TYPE i.
172 | ENDCLASS.
173 |
174 | CLASS lcl_result IMPLEMENTATION.
175 | METHOD constructor.
176 | mv_param = iv_param.
177 | mv_result = iv_result.
178 | ENDMETHOD.
179 |
180 | METHOD get.
181 | rv_result = |{ mv_param } -> { mv_result }|.
182 | ENDMETHOD.
183 | ENDCLASS.
184 | ```
185 |
186 |
187 | **Attention:**
188 | Objects of the **lcl_task** and **lcl_result** classes are serialized/deserialized at runtime, so avoid using static attributes.
189 | Static attributes belong to the class, not the object. Their contents will be lost after serialization/deserialization.
190 |
191 | So, the objects *Context*, *Task*, and *Result* are described.
192 | Now, let's have a look at example:
193 |
194 |
195 |
196 | Show code...
197 |
198 | ```abap
199 | CONSTANTS lc_server_group TYPE rfcgr VALUE 'parallel_generators'.
200 | DATA lo_result TYPE REF TO lcl_result.
201 |
202 | " Create collection of tasks
203 | DATA(lo_tasks) = NEW zcl_capi_collection( ).
204 |
205 | DO 10 TIMES.
206 |
207 | DATA(lo_context) = NEW lcl_context( VALUE lcl_context=>ty_params( param = sy-index ) ).
208 | DATA(lo_task) = NEW lcl_task( lo_context ).
209 | lo_tasks->zif_capi_collection~add( lo_task ).
210 |
211 | ENDDO.
212 |
213 | DATA(lo_message_handler) = NEW zcl_capi_message_handler( ).
214 | DATA(lv_max_no_of_tasks) = zcl_capi_thread_pool_executor=>max_no_of_tasks( lc_server_group ).
215 |
216 | DATA(lo_executor) = zcl_capi_executors=>new_fixed_thread_pool( iv_server_group = lc_server_group
217 | iv_n_threads = lv_max_no_of_tasks
218 | io_capi_message_handler = lo_message_handler ).
219 | TRY.
220 | DATA(lo_results) = lo_executor->zif_capi_executor_service~invoke_all( lo_tasks ).
221 |
222 | IF lo_message_handler->zif_capi_message_handler~has_messages( ) = abap_false.
223 |
224 | DATA(lo_results_iterator) = lo_results->get_iterator( ).
225 |
226 | WHILE lo_results_iterator->has_next( ).
227 | lo_result ?= lo_results_iterator->next( ).
228 | WRITE: / lo_result->get( ).
229 | ENDWHILE.
230 |
231 | ENDIF.
232 |
233 | CATCH zcx_capi_tasks_invocation INTO DATA(lo_capi_tasks_invocation).
234 | WRITE lo_capi_tasks_invocation->get_text( ).
235 | ENDTRY.
236 | ```
237 |
238 |
239 | 1. First, create *Tasks collection* **lo_tasks**
240 | 2. Next, create a *Task* **lo_task** and add it to the *Tasks collection* **lo_tasks**
241 | 3. Create a message handler **lo_message_handler** (optional)
242 | 4. Now we come to the most important part of the API of the “executor service” concept. The executor asynchronously executes the tasks passed to it.
243 | In the example, we call the static method **zcl_capi_executors=>new_fixed_thread_pool**, which returns a lo_executor with a fixed number of threads. This method has 4 parameters:
244 |
245 | | Parameter name | Optional | Description |
246 | | :-------------------------- | :------: | :-------------------------------------------------------------|
247 | | iv_server_group | | server group (tcode: RZ12) |
248 | | iv_max_no_of_tasks | | maximum number of parallel tasks |
249 | | iv_no_resubmission_on_error | | flag "**true**" - don't restart the task in case of an error |
250 | | io_capi_message_handler | X | an object that will contain error messages (if they occurred) |
251 |
252 | The **lo_executor** object has only one interface method **zif_capi_executor_service~invoke_all ()**, which takes as input a **collection of tasks** and returns a **collection of results** **lo_results** (the approach was taken from **java.util.concurrent.***).
253 |
254 | 5. The *Collection of results* **lo_results** has an iterator, using which we easily get the **lo_result** and call the **get()** method from them.
255 |
256 | As a result, we did't have to create an RFC functional module, describe the parallelization process, etc.
257 | All we did was describe what the *Task* and *Result* are.
258 |
259 | **Result of execution:**
260 |
261 | 
262 |
263 | An example of using the `ABAP Concurrency API` can be found in the **ZCONCURRENCY_API_EXAMPLE** report.
264 |
265 | ## Using in the HCM module
266 | To simplify the work with the ABAP Concurrency API in the HCM module, it is proposed to use the implementation of the Facade structural pattern - ZCAPI_FACADE_HCM package. The Facade design pattern encapsulates the breakdown of personnel numbers into batches, the creation of *Task* objects, and the retrieval of the result.
267 |
268 | Let's consider a simple task:
269 |
270 | *Get the full name of employees by personnel numbers.*
271 |
272 | First, we will also create 3 classes: *Context*, *Task* and *Result*.
273 |
274 | 1. **lcl_contex**, an object of this class will encapsulate the task parameters. Note that the *lcl_contex* class must inherit from the abstract class **zcl_capi_facade_hcm_abstr_cntx**. When implementing, you must override the *constructor* method.
275 |
276 |
277 | Show code...
278 |
279 | ```abap
280 | CLASS lcl_context DEFINITION INHERITING FROM zcl_capi_facade_hcm_abstr_cntx FINAL.
281 | PUBLIC SECTION.
282 |
283 | TYPES:
284 | BEGIN OF ty_params,
285 | begda TYPE d,
286 | endda TYPE d,
287 | END OF ty_params.
288 |
289 | METHODS:
290 | constructor IMPORTING is_params TYPE ty_params,
291 | get_params RETURNING VALUE(rs_params) TYPE ty_params.
292 |
293 | PRIVATE SECTION.
294 | DATA: ms_params TYPE ty_params.
295 |
296 | ENDCLASS.
297 |
298 | CLASS lcl_context IMPLEMENTATION.
299 | METHOD constructor.
300 | super->constructor( ).
301 | ms_params = is_params.
302 | ENDMETHOD.
303 |
304 | METHOD get_params.
305 | rs_params = ms_params.
306 | ENDMETHOD.
307 | ENDCLASS.
308 | ```
309 |
310 |
311 | 2. **lcl_task**, describes the *Task* object. Contains business logic (getting full name by personnel number of an employee).
312 | The **lcl_task** class must inherit from the **zcl_capi_facade_hcm_abstr_task** class. You must implement the *constructor* method and override the *zif_capi_callable~call* method.
313 |
314 |
315 | Show code...
316 |
317 | ```abap
318 | CLASS lcl_task DEFINITION INHERITING FROM zcl_capi_facade_hcm_abstr_task FINAL.
319 | PUBLIC SECTION.
320 |
321 | METHODS:
322 | constructor IMPORTING io_context TYPE REF TO zcl_capi_facade_hcm_abstr_cntx,
323 | zif_capi_callable~call REDEFINITION.
324 |
325 | PRIVATE SECTION.
326 | DATA ms_params TYPE lcl_context=>ty_params.
327 |
328 | ENDCLASS.
329 |
330 | CLASS lcl_task IMPLEMENTATION.
331 | METHOD constructor.
332 | DATA lo_context TYPE REF TO lcl_context.
333 |
334 | " Set Pernrs numbers to mt_pernrs of Task
335 | super->constructor( io_context ).
336 |
337 | " Set Context parameters
338 | lo_context ?= io_context.
339 | ms_params = lo_context->get_params( ).
340 |
341 | ENDMETHOD.
342 |
343 | METHOD zif_capi_callable~call.
344 |
345 | DATA lt_employees TYPE lcl_result=>ty_t_employees.
346 | DATA ls_employees LIKE LINE OF lt_employees.
347 |
348 | " Simulation of reading the full name of employees by their personnel numbers.
349 | " The ms_params attribute is available here.
350 | " We won't be using it in this example, but you can.
351 |
352 | LOOP AT mt_pernrs ASSIGNING FIELD-SYMBOL().
353 | ls_employees-pernr = -low.
354 |
355 | CASE -low.
356 | WHEN 00000001.
357 | ls_employees-ename = 'John Doe 1'.
358 | WHEN 00000002.
359 | ls_employees-ename = 'John Doe 2'.
360 | WHEN 00000003.
361 | ls_employees-ename = 'John Doe 3'.
362 | WHEN 00000004.
363 | ls_employees-ename = 'John Doe 4'.
364 | WHEN 00000005.
365 | ls_employees-ename = 'John Doe 5'.
366 | WHEN 00000006.
367 | ls_employees-ename = 'John Doe 6'.
368 | WHEN 00000007.
369 | ls_employees-ename = 'John Doe 7'.
370 | WHEN 00000008.
371 | ls_employees-ename = 'John Doe 8'.
372 | WHEN 00000009.
373 | ls_employees-ename = 'John Doe 9'.
374 | WHEN 00000010.
375 | ls_employees-ename = 'John Doe 10'.
376 | WHEN OTHERS.
377 | ENDCASE.
378 |
379 | INSERT ls_employees INTO TABLE lt_employees.
380 | ENDLOOP.
381 |
382 | ro_result = NEW lcl_result( lt_employees ).
383 |
384 | ENDMETHOD.
385 | ENDCLASS.
386 | ```
387 |
388 |
389 |
390 | 3. **lcl_result** describes *Result* of task execution.
391 | This class must implement the **zif_capi_facade_hcm_result** interface. Otherwise, you can describe it in any way.
392 |
393 |
394 |
395 | Show code...
396 |
397 | ```abap
398 | CLASS lcl_result DEFINITION FINAL.
399 | PUBLIC SECTION.
400 | INTERFACES zif_capi_facade_hcm_result.
401 |
402 | TYPES:
403 | BEGIN OF ty_employees,
404 | pernr TYPE n LENGTH 8,
405 | ename TYPE string,
406 | END OF ty_employees,
407 |
408 | ty_t_employees TYPE STANDARD TABLE OF ty_employees WITH KEY pernr.
409 |
410 | METHODS constructor IMPORTING it_employees TYPE ty_t_employees.
411 |
412 | PRIVATE SECTION.
413 | DATA mt_employees TYPE ty_t_employees.
414 |
415 | ENDCLASS.
416 |
417 | CLASS lcl_result IMPLEMENTATION.
418 | METHOD constructor.
419 | mt_employees = it_employees.
420 | ENDMETHOD.
421 |
422 | METHOD zif_capi_facade_hcm_result~get.
423 | et_result = mt_employees.
424 | ENDMETHOD. "get
425 | ENDCLASS.
426 | ```
427 |
428 |
429 | **Attention:**
430 | Class objects **lcl_task** and **lcl_result** are serialized/deserialized at runtime, so avoid using static attributes.
431 |
432 | So, the objects *Context*, *Task*, and *Result* are described.
433 | Now, let's have a look at example:
434 |
435 |
436 |
437 | Show code...
438 |
439 | ```abap
440 | DATA lt_employees TYPE lcl_result=>ty_t_employees.
441 |
442 | " 2 Pernr number per task. For example only.
443 | " '200' will be fine.
444 | DATA(lv_package_size) = 2.
445 |
446 | DATA(ls_params) = VALUE lcl_context=>ty_params( begda = sy-datum
447 | endda = sy-datum ).
448 | DATA(lo_context) = NEW lcl_context( ls_params ).
449 |
450 | DATA(lo_capi_facade_hcm) = NEW zcl_capi_facade_hcm( io_context = lo_context
451 | it_pernrs = gt_pernrs
452 | iv_task_class_name = 'LCL_TASK'
453 | iv_package_size = lv_package_size ).
454 | TRY.
455 | lo_capi_facade_hcm->execute( IMPORTING et_result = lt_employees ).
456 |
457 | WRITE `PERNR ENAME`.
458 | LOOP AT lt_employees ASSIGNING FIELD-SYMBOL().
459 | WRITE: / -pernr, -ename.
460 | ENDLOOP.
461 |
462 | CATCH zcx_capi_tasks_invocation INTO DATA(lo_capi_tasks_invocation).
463 | WRITE lo_capi_tasks_invocation->get_text( ).
464 | ENDTRY.
465 | ```
466 |
467 |
468 | 1. First, create *Contexts* **lo_context**, which contains parameters for launching *Tasks*.
469 | 2. Next, create *Facade* **lo_capi_facade_hcm**, the constructor of which has 4 parameters:
470 |
471 | | Parameter name | Description |
472 | | :-------------------------- | :-------------------------------------------------------------------|
473 | | io_context | This is an object containing the parameters for starting the task |
474 | | it_pernrs | This is the personnel number range |
475 | | iv_task_class_name | The name of the Task class. |
476 | | iv_package_size | This is the number of personnel numbers per task. |
477 |
478 | 3. Call the *execute()* method on the **lo_capi_facade_hcm** object, which starts tasks for parallel execution and returns the result.
479 |
480 | The maximum number of running in parallel tasks is calculated as 40% of the number of free dialog processes (DIA, sm50).
481 | That's all you need to do.
482 |
483 | **Result of execution:**
484 |
485 | 
486 |
487 | The considered example of using the Facade for the `ABAP Concurrency API` can be found in the **ZCAPI_FACADE_HCM_EXAMPLE** report.
488 |
489 | ## Diagrams
490 |
491 | UML Class Diagram ABAP Concurrency API
492 |
493 |
494 |
495 | UML Class Diagram ABAP Concurrency API for HCM module
496 |
497 |
498 |
499 | UML Sequence Diagram
500 |
501 |
502 |
503 | ## Dependencies
504 | SPTA package required.
505 |
506 | ## Limitations:
507 | Batch input is not supported.
508 | This limitation is related to the use of SPTA Framework.
509 | See the note [734205](https://launchpad.support.sap.com/#/notes/734205) and [710920](https://launchpad.support.sap.com/#/notes/710920) for details.
510 |
511 | ## How to contribute
512 | [This instruction](https://docs.abapgit.org/guide-contributing.html) will help you.
513 |
514 | ## Got questions?
515 | If you have questions or general suggestions, don't hesitate to submit a new [(GitHub issue)](https://github.com/victorizbitskiy/zconcurrency_api/issues/new).
516 |
517 | ## Logo
518 | Project logo designed by macrovector/Freepik
519 |
--------------------------------------------------------------------------------
/abaplint.json:
--------------------------------------------------------------------------------
1 | {
2 | "global": {
3 | "files": "/src/**/*.*",
4 | "skipGeneratedGatewayClasses": true,
5 | "skipGeneratedPersistentClasses": true,
6 | "skipGeneratedFunctionGroups": true
7 | },
8 | "dependencies": [
9 | {
10 | "url": "https://github.com/abaplint/deps",
11 | "folder": "/deps",
12 | "files": "/src/**/*.*"
13 | }
14 | ],
15 | "syntax": {
16 | "version": "v700",
17 | "errorNamespace": "^(Z|Y|LT?CL_|TY_|LIF_|.*CAPI)",
18 | "globalConstants": [
19 | "abap_func_exporting",
20 | "abap_func_tables",
21 | "cssf_formtype_text",
22 | "icon_abap",
23 | "icon_display_text",
24 | "icon_folder",
25 | "icon_led_green",
26 | "icon_led_inactive",
27 | "icon_led_red",
28 | "icon_led_yellow",
29 | "icon_message_information",
30 | "icon_okay",
31 | "icon_set_state",
32 | "icon_stack",
33 | "icon_system_help",
34 | "icon_workflow_fork",
35 | "seoc_category_exception",
36 | "seoc_category_webdynpro_class",
37 | "seoc_exposure_private",
38 | "seoc_exposure_protected",
39 | "seoc_exposure_public",
40 | "seoc_version_active",
41 | "seoc_version_inactive",
42 | "seok_access_free",
43 | "seok_access_modify",
44 | "seok_pgmid_r3tr",
45 | "seop_ext_class_locals_def",
46 | "seop_ext_class_locals_imp",
47 | "seop_ext_class_macros",
48 | "seop_ext_class_testclasses",
49 | "seop_incextapp_definition",
50 | "seop_incextapp_implementation",
51 | "seop_incextapp_macros",
52 | "seop_incextapp_testclasses",
53 | "sews_c_vif_version",
54 | "skwfc_obtype_folder",
55 | "skwfc_obtype_loio",
56 | "so2_controller",
57 | "ststc_c_type_dialog",
58 | "ststc_c_type_object",
59 | "ststc_c_type_parameters",
60 | "ststc_c_type_report",
61 | "swbm_c_op_delete_no_dialog",
62 | "swbm_c_type_ddic_db_tabxinx",
63 | "swbm_c_type_wdy_application",
64 | "swbm_version_active",
65 | "swbm_version_inactive",
66 | "swfco_org_standard_task",
67 | "swfco_org_workflow_template",
68 | "wbmr_c_skwf_folder_class",
69 | "wdyn_limu_component_controller",
70 | "wdyn_limu_component_definition",
71 | "wdyn_limu_component_view"
72 | ],
73 | "globalMacros": []
74 | },
75 | "rules": {
76 | "use_class_based_exceptions": true,
77 | "uncaught_exception": true,
78 | "intf_referencing_clas": false,
79 | "method_implemented_twice": true,
80 | "parser_702_chaining": true,
81 | "sy_modification": false,
82 | "call_transaction_authority_check": true,
83 | "function_module_recommendations": false,
84 | "method_overwrites_builtin": false,
85 | "omit_parameter_name": false,
86 | "omit_receiving": true,
87 | "unused_methods": true,
88 | "identical_contents": false,
89 | "many_parenthesis": true,
90 | "prefer_xsdbool": true,
91 | "prefer_is_not": false,
92 | "use_bool_expression": true,
93 | "check_subrc": false,
94 | "cyclomatic_complexity": {
95 | "max": 25
96 | },
97 | "identical_conditions": true,
98 | "use_line_exists": true,
99 | "line_break_style": true,
100 | "forbidden_pseudo_and_pragma": {
101 | "ignoreGlobalClassDefinition": true,
102 | "ignoreGlobalInterface": true,
103 | "pragmas": ["##NO_TEXT"],
104 | "pseudo": ["#EC NOTEXT"]
105 | },
106 | "unused_types": true,
107 | "begin_single_include": true,
108 | "names_no_dash": true,
109 | "parser_missing_space": true,
110 | "prefer_inline": false,
111 | "reduce_string_templates": true,
112 | "downport": false,
113 | "line_break_multiple_parameters": true,
114 | "unknown_types": true,
115 | "forbidden_void_type": {
116 | "check": ["^stringtab$", "^SYCHAR01$", "^char2$", "^char20$", "^int4$", "^SYREPID$",
117 | "^flag$", "^char12$", "^char10$", "^char70$", "^char4$", "^sydatum$", "^syuzeit$",
118 | "^syst_title$", "^sychar70$", "^char30$", "^char50$",
119 | "^numc2$", "^sap_bool$", "^SYCHAR10$", "^sylangu$"]
120 | },
121 | "forbidden_identifier": true,
122 | "try_without_catch": true,
123 | "unused_variables": false,
124 | "prefix_is_current_class": true,
125 | "allowed_object_naming": true,
126 | "check_comments": false,
127 | "fully_type_constants": true,
128 | "keep_single_parameter_on_one_line": true,
129 | "prefer_returning_to_exporting": true,
130 | "selection_screen_naming": true,
131 | "sicf_consistency": true,
132 | "sql_escape_host_variables": true,
133 | "xml_consistency": true,
134 | "check_no_handler_pragma": true,
135 | "newline_between_methods": false,
136 | "chain_mainly_declarations": {
137 | "definitions": true,
138 | "write": true,
139 | "move": true,
140 | "refresh": true,
141 | "unassign": true,
142 | "clear": true,
143 | "hide": true,
144 | "free": true,
145 | "include": true,
146 | "check": true
147 | },
148 | "check_abstract": true,
149 | "check_text_elements": true,
150 | "types_naming": {
151 | "pattern": "^TY_.+$",
152 | "exclude": ["/json/"]
153 | },
154 | "7bit_ascii": {
155 | },
156 | "abapdoc": false,
157 | "check_ddic": true,
158 | "check_include": true,
159 | "allowed_object_types": true,
160 | "ambiguous_statement": false,
161 | "avoid_use": {
162 | "define": true,
163 | "statics": false,
164 | "defaultKey": true,
165 | "break": true,
166 | "describeLines": true
167 | },
168 | "begin_end_names": true,
169 | "check_transformation_exists": false,
170 | "check_syntax": true,
171 | "class_attribute_names": {
172 | "ignoreExceptions": true,
173 | "ignoreInterfaces": false,
174 | "statics": "^G._.*$",
175 | "ignoreLocal": false,
176 | "constants": "",
177 | "instance": "^M._.*$"
178 | },
179 | "cloud_types": true,
180 | "colon_missing_space": true,
181 | "commented_code": {
182 | "allowIncludeInFugr": false,
183 | "exclude": ["otgr"]
184 | },
185 | "constructor_visibility_public": true,
186 | "contains_tab": true,
187 | "definitions_top": {
188 | "exclude": ["/json/"]
189 | },
190 | "description_empty": true,
191 | "double_space": false,
192 | "empty_line_in_statement": {
193 | "allowChained": true
194 | },
195 | "empty_statement": true,
196 | "empty_structure": {
197 | "loop": true,
198 | "if": false,
199 | "try": true,
200 | "while": true,
201 | "case": true,
202 | "select": true,
203 | "do": true,
204 | "at": true
205 | },
206 | "exit_or_check": true,
207 | "exporting": true,
208 | "form_tables_obsolete": false,
209 | "functional_writing": {
210 | "ignoreExceptions": true
211 | },
212 | "global_class": true,
213 | "identical_form_names": true,
214 | "if_in_if": true,
215 | "implement_methods": false,
216 | "in_statement_indentation": false,
217 | "indentation": {
218 | "ignoreExceptions": true,
219 | "alignTryCatch": false,
220 | "globalClassSkipFirst": false,
221 | "ignoreGlobalClassDefinition": false,
222 | "ignoreGlobalInterface": false
223 | },
224 | "inline_data_old_versions": true,
225 | "keyword_case": {
226 | "style": "upper",
227 | "ignoreExceptions": true,
228 | "ignoreLowerClassImplmentationStatement": true,
229 | "ignoreGlobalClassDefinition": false,
230 | "ignoreGlobalInterface": false,
231 | "ignoreKeywords": [],
232 | "ignoreGlobalClassBoundaries": false,
233 | "ignoreFunctionModuleName": false
234 | },
235 | "line_length": {
236 | "length": 120,
237 | },
238 | "line_only_punc": {
239 | "ignoreExceptions": true
240 | },
241 | "local_class_naming": {
242 | "exception": "^LCX_.*$",
243 | "local": "^LCL_.*$",
244 | "test": "^LT.+$"
245 | },
246 | "local_testclass_location": true,
247 | "local_variable_names": {
248 | "expectedData": "^L._.*$",
249 | "expectedConstant": "^LC_.*$",
250 | "expectedFS": "^$",
251 | "exclude": ["/json/"]
252 | },
253 | "main_file_contents": true,
254 | "max_one_statement": true,
255 | "message_exists": false,
256 | "method_length": {
257 | "statements": 100,
258 | "ignoreTestClasses": false,
259 | "errorWhenEmpty": false
260 | },
261 | "method_parameter_names": {
262 | "ignoreExceptions": true,
263 | "importing": "^I._.*$",
264 | "returning": "^R._.*$",
265 | "changing": "^C._.*$",
266 | "exporting": "^E._.*$",
267 | "ignoreNames": [
268 | "P_TASK"
269 | ],
270 | "exclude": ["/json/"]
271 | },
272 | "mix_returning": true,
273 | "msag_consistency": true,
274 | "nesting": {
275 | "depth": 6
276 | },
277 | "no_public_attributes": false,
278 | "object_naming": {
279 | "clas": "^ZC(L|X)\\_CAPI\\_",
280 | "intf": "^ZIF\\_CAPI\\_",
281 | "prog": "^Z(CAPI|CONCURRENCY_API)",
282 | "fugr": "^Z(CAPI)",
283 | "tabl": "^Z",
284 | "ttyp": "^Z",
285 | "dtel": "^Z",
286 | "doma": "^Z",
287 | "msag": "^Z",
288 | "tran": "^Z",
289 | "enqu": "^EZ",
290 | "auth": "^Z",
291 | "pinf": "^Z",
292 | "idoc": "^Z",
293 | "ssfo": "^Z",
294 | "ssst": "^Z",
295 | "shlp": "^Z",
296 | "xslt": "^Z"
297 | },
298 | "obsolete_statement": {
299 | "refresh": true,
300 | "compute": true,
301 | "add": true,
302 | "subtract": true,
303 | "multiply": true,
304 | "typePools": true,
305 | "load": true,
306 | "move": true,
307 | "divide": true,
308 | "fieldSymbolStructure": true,
309 | "requested": true,
310 | "setExtended": true,
311 | "withHeaderLine": true,
312 | "occurs": true
313 | },
314 | "parser_error": {},
315 | "preferred_compare_operator": {
316 | "badOperators": [
317 | "EQ",
318 | "><",
319 | "NE",
320 | "GE",
321 | "GT",
322 | "LT",
323 | "LE"
324 | ]
325 | },
326 | "release_idoc": true,
327 | "remove_descriptions": {
328 | "ignoreWorkflow": false,
329 | "ignoreExceptions": false,
330 | "exclude": ["/json/"]
331 | },
332 | "rfc_error_handling": false,
333 | "sequential_blank": {
334 | "lines": 4
335 | },
336 | "short_case": {
337 | "length": 1,
338 | "allow": [
339 | "iv_action",
340 | "sy"
341 | ]
342 | },
343 | "space_before_colon": true,
344 | "space_before_dot": {
345 | "ignoreGlobalDefinition": true,
346 | "ignoreExceptions": true
347 | },
348 | "start_at_tab": true,
349 | "superclass_final": true,
350 | "tabl_enhancement_category": true,
351 | "type_form_parameters": true,
352 | "unreachable_code": true,
353 | "use_new": true,
354 | "when_others_last": true,
355 | "whitespace_end": true
356 | }
357 | }
358 |
--------------------------------------------------------------------------------
/docs/img/UML Class Dia ABAP CAPI for HCM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorizbitskiy/zconcurrency_api/1ddbe9e75d4849f11b12594af23ab5e4c5ce01eb/docs/img/UML Class Dia ABAP CAPI for HCM.png
--------------------------------------------------------------------------------
/docs/img/UML Class Dia.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorizbitskiy/zconcurrency_api/1ddbe9e75d4849f11b12594af23ab5e4c5ce01eb/docs/img/UML Class Dia.png
--------------------------------------------------------------------------------
/docs/img/UML Sequence Dia.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorizbitskiy/zconcurrency_api/1ddbe9e75d4849f11b12594af23ab5e4c5ce01eb/docs/img/UML Sequence Dia.png
--------------------------------------------------------------------------------
/docs/img/percent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorizbitskiy/zconcurrency_api/1ddbe9e75d4849f11b12594af23ab5e4c5ce01eb/docs/img/percent.png
--------------------------------------------------------------------------------
/docs/img/result HCM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorizbitskiy/zconcurrency_api/1ddbe9e75d4849f11b12594af23ab5e4c5ce01eb/docs/img/result HCM.png
--------------------------------------------------------------------------------
/docs/img/result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victorizbitskiy/zconcurrency_api/1ddbe9e75d4849f11b12594af23ab5e4c5ce01eb/docs/img/result.png
--------------------------------------------------------------------------------
/logo/octo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
150 |
--------------------------------------------------------------------------------
/src/package.devc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ABAP Сoncurrency API
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/zcapi_facade/package.devc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Facade Pattern
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/package.devc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Facade Pattern HCM
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/zcapi_facade_hcm_example.prog.abap:
--------------------------------------------------------------------------------
1 | *&---------------------------------------------------------------------*
2 | *& Report ZCAPI_FACADE_HCM_EXAMPLE
3 | *&---------------------------------------------------------------------*
4 | *&
5 | *&---------------------------------------------------------------------*
6 | REPORT zcapi_facade_hcm_example.
7 |
8 | INCLUDE zcapi_facade_hcm_example_cld.
9 | INCLUDE zcapi_facade_hcm_example_cli.
10 |
11 | START-OF-SELECTION.
12 | lcl_app=>start_of_selection( ).
13 |
14 | END-OF-SELECTION.
15 | lcl_app=>end_of_selection( ).
16 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/zcapi_facade_hcm_example.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCAPI_FACADE_HCM_EXAMPLE
7 | 1
8 | K
9 | E
10 | X
11 | X
12 |
13 |
14 |
15 | R
16 | Program ZCAPI_FACADE_HCM_EXAMPLE
17 | 32
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/zcapi_facade_hcm_example_cld.prog.abap:
--------------------------------------------------------------------------------
1 | *&---------------------------------------------------------------------*
2 | *& Include ZCAPI_FACADE_HCM_EXAMPLE_CLD
3 | *&---------------------------------------------------------------------*
4 | CLASS lcl_app DEFINITION FINAL.
5 | PUBLIC SECTION.
6 |
7 | CLASS-DATA:
8 | gt_pernrs TYPE zif_capi_facade_hcm_context=>ty_t_pernrs.
9 |
10 | CLASS-METHODS:
11 | end_of_selection,
12 | start_of_selection.
13 |
14 | ENDCLASS.
15 | *----------------------------------------------------------------------*
16 | * CLASS lcl_context DEFINITION
17 | *----------------------------------------------------------------------*
18 | *
19 | *----------------------------------------------------------------------*
20 | CLASS lcl_context DEFINITION INHERITING FROM zcl_capi_facade_hcm_abstr_cntx FINAL.
21 | PUBLIC SECTION.
22 |
23 | TYPES:
24 | BEGIN OF ty_params,
25 | begda TYPE d,
26 | endda TYPE d,
27 | END OF ty_params.
28 |
29 | METHODS:
30 | constructor IMPORTING is_params TYPE ty_params,
31 | get_params RETURNING VALUE(rs_params) TYPE ty_params.
32 |
33 | PRIVATE SECTION.
34 |
35 | DATA ms_params TYPE ty_params.
36 |
37 | ENDCLASS.
38 | *----------------------------------------------------------------------*
39 | * CLASS lcl_task DEFINITION
40 | *----------------------------------------------------------------------*
41 | *
42 | *----------------------------------------------------------------------*
43 | CLASS lcl_task DEFINITION INHERITING FROM zcl_capi_facade_hcm_abstr_task FINAL.
44 | PUBLIC SECTION.
45 |
46 | METHODS:
47 | constructor IMPORTING io_context TYPE REF TO zcl_capi_facade_hcm_abstr_cntx,
48 | zif_capi_callable~call REDEFINITION.
49 |
50 | PRIVATE SECTION.
51 |
52 | DATA ms_params TYPE lcl_context=>ty_params.
53 |
54 | ENDCLASS.
55 | *----------------------------------------------------------------------*
56 | * CLASS lcl_result DEFINITION
57 | *----------------------------------------------------------------------*
58 | *
59 | *----------------------------------------------------------------------*
60 | CLASS lcl_result DEFINITION FINAL.
61 | PUBLIC SECTION.
62 |
63 | INTERFACES zif_capi_facade_hcm_result.
64 |
65 | TYPES:
66 | BEGIN OF ty_employees,
67 | pernr TYPE n LENGTH 8,
68 | ename TYPE string,
69 | END OF ty_employees,
70 |
71 | ty_t_employees TYPE STANDARD TABLE OF ty_employees WITH KEY pernr.
72 |
73 | METHODS:
74 | constructor IMPORTING it_employees TYPE ty_t_employees.
75 |
76 | PRIVATE SECTION.
77 |
78 | DATA mt_employees TYPE ty_t_employees.
79 |
80 | ENDCLASS.
81 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/zcapi_facade_hcm_example_cld.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCAPI_FACADE_HCM_EXAMPLE_CLD
7 | I
8 | K
9 | E
10 | X
11 |
12 |
13 |
14 | R
15 | Include ZCAPI_FACADE_HCM_DEMO_CLD
16 | 33
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/zcapi_facade_hcm_example_cli.prog.abap:
--------------------------------------------------------------------------------
1 | *&---------------------------------------------------------------------*
2 | *& Include ZCAPI_FACADE_HCM_EXAMPLE_CLI
3 | *&---------------------------------------------------------------------*
4 | CLASS lcl_app IMPLEMENTATION.
5 | METHOD start_of_selection.
6 |
7 | DATA ls_pernrs LIKE LINE OF gt_pernrs.
8 |
9 | " Modeling the selection of personnel numbers
10 | DO 10 TIMES.
11 | ls_pernrs-sign = 'I'.
12 | ls_pernrs-option = 'EQ'.
13 | ls_pernrs-low = sy-index.
14 | APPEND ls_pernrs TO gt_pernrs.
15 | ENDDO.
16 |
17 | ENDMETHOD.
18 |
19 | METHOD end_of_selection.
20 |
21 | DATA lv_package_size TYPE i.
22 | DATA ls_params TYPE lcl_context=>ty_params.
23 | DATA lo_context TYPE REF TO lcl_context.
24 | DATA lo_capi_facade_hcm TYPE REF TO zcl_capi_facade_hcm.
25 | DATA lt_employees TYPE lcl_result=>ty_t_employees.
26 | DATA lo_capi_tasks_invocation TYPE REF TO zcx_capi_tasks_invocation.
27 | DATA lv_message_text TYPE string.
28 |
29 | FIELD-SYMBOLS LIKE LINE OF lt_employees.
30 |
31 | " 2 Pernr number per task. For example only.
32 | " Use the default '1000'.
33 | lv_package_size = 2.
34 |
35 | ls_params-begda = sy-datum.
36 | ls_params-endda = sy-datum.
37 |
38 | CREATE OBJECT lo_context
39 | EXPORTING
40 | is_params = ls_params.
41 |
42 | CREATE OBJECT lo_capi_facade_hcm
43 | EXPORTING
44 | io_context = lo_context
45 | it_pernrs = gt_pernrs
46 | iv_task_class_name = 'LCL_TASK'
47 | iv_package_size = lv_package_size.
48 |
49 | TRY.
50 | lo_capi_facade_hcm->execute( IMPORTING et_result = lt_employees ).
51 |
52 | WRITE: `PERNR ENAME`.
53 | LOOP AT lt_employees ASSIGNING .
54 | WRITE: / -pernr, -ename.
55 | ENDLOOP.
56 |
57 | CATCH zcx_capi_tasks_invocation INTO lo_capi_tasks_invocation.
58 | lv_message_text = lo_capi_tasks_invocation->get_text( ).
59 | WRITE lv_message_text.
60 | ENDTRY.
61 |
62 | ENDMETHOD.
63 | ENDCLASS.
64 | *----------------------------------------------------------------------*
65 | * CLASS lcl_context IMPLEMENTATION
66 | *----------------------------------------------------------------------*
67 | *
68 | *----------------------------------------------------------------------*
69 | CLASS lcl_context IMPLEMENTATION.
70 | METHOD constructor.
71 |
72 | super->constructor( ).
73 | ms_params = is_params.
74 |
75 | ENDMETHOD.
76 |
77 | METHOD get_params.
78 | rs_params = ms_params.
79 | ENDMETHOD.
80 | ENDCLASS.
81 |
82 | *----------------------------------------------------------------------*
83 | * CLASS lcl_task DEFINITION
84 | *----------------------------------------------------------------------*
85 | *
86 | *----------------------------------------------------------------------*
87 | CLASS lcl_task IMPLEMENTATION.
88 | METHOD constructor.
89 |
90 | DATA lo_context TYPE REF TO lcl_context.
91 |
92 | " Set Pernrs numbers to mt_pernrs of Task
93 | super->constructor( io_context ).
94 |
95 | " Set Context parameters
96 | lo_context ?= io_context.
97 | ms_params = lo_context->get_params( ).
98 |
99 | ENDMETHOD.
100 |
101 | METHOD zif_capi_callable~call.
102 |
103 | DATA lt_employees TYPE lcl_result=>ty_t_employees.
104 | DATA ls_employees LIKE LINE OF lt_employees.
105 |
106 | FIELD-SYMBOLS LIKE LINE OF mt_pernrs.
107 |
108 | " Simulation of reading the full name of employees by their personnel numbers.
109 | " The ms_params attribute is available here.
110 | " We won't be using it in this example, but you can.
111 |
112 | LOOP AT mt_pernrs ASSIGNING .
113 | ls_employees-pernr = -low.
114 |
115 | CASE -low.
116 | WHEN 00000001.
117 | ls_employees-ename = 'John Doe 1'.
118 | WHEN 00000002.
119 | ls_employees-ename = 'John Doe 2'.
120 | WHEN 00000003.
121 | ls_employees-ename = 'John Doe 3'.
122 | WHEN 00000004.
123 | ls_employees-ename = 'John Doe 4'.
124 | WHEN 00000005.
125 | ls_employees-ename = 'John Doe 5'.
126 | WHEN 00000006.
127 | ls_employees-ename = 'John Doe 6'.
128 | WHEN 00000007.
129 | ls_employees-ename = 'John Doe 7'.
130 | WHEN 00000008.
131 | ls_employees-ename = 'John Doe 8'.
132 | WHEN 00000009.
133 | ls_employees-ename = 'John Doe 9'.
134 | WHEN 00000010.
135 | ls_employees-ename = 'John Doe 10'.
136 | WHEN OTHERS.
137 | ENDCASE.
138 |
139 | INSERT ls_employees INTO TABLE lt_employees.
140 | ENDLOOP.
141 |
142 | CREATE OBJECT ro_result
143 | TYPE
144 | lcl_result
145 | EXPORTING
146 | it_employees = lt_employees.
147 |
148 | ENDMETHOD.
149 | ENDCLASS.
150 |
151 | *----------------------------------------------------------------------*
152 | * CLASS lcl_result IMPLEMENTATION
153 | *----------------------------------------------------------------------*
154 | *
155 | *----------------------------------------------------------------------*
156 | CLASS lcl_result IMPLEMENTATION.
157 | METHOD constructor.
158 | mt_employees = it_employees.
159 | ENDMETHOD.
160 |
161 | METHOD zif_capi_facade_hcm_result~get.
162 | et_result = mt_employees.
163 | ENDMETHOD.
164 | ENDCLASS.
165 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/zcapi_facade_hcm_example_cli.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCAPI_FACADE_HCM_EXAMPLE_CLI
7 | I
8 | K
9 | E
10 | X
11 |
12 |
13 |
14 | R
15 | Include ZCAPI_FACADE_HCM_DEMO_CLI
16 | 33
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/zcl_capi_facade_hcm.clas.abap:
--------------------------------------------------------------------------------
1 | CLASS zcl_capi_facade_hcm DEFINITION
2 | PUBLIC
3 | FINAL
4 | CREATE PUBLIC .
5 |
6 | PUBLIC SECTION.
7 |
8 | METHODS constructor
9 | IMPORTING
10 | !io_context TYPE REF TO zcl_capi_facade_hcm_abstr_cntx
11 | !it_pernrs TYPE zif_capi_facade_hcm_context=>ty_t_pernrs
12 | !iv_task_class_name TYPE string
13 | !iv_package_size TYPE i DEFAULT 1000 .
14 | METHODS execute
15 | IMPORTING
16 | !iv_server_group TYPE rfcgr DEFAULT 'parallel_generators'
17 | EXPORTING
18 | !et_result TYPE ANY TABLE
19 | RAISING
20 | zcx_capi_tasks_invocation .
21 | PROTECTED SECTION.
22 | PRIVATE SECTION.
23 |
24 | DATA mo_context TYPE REF TO zcl_capi_facade_hcm_abstr_cntx .
25 | DATA mt_pernrs TYPE zif_capi_facade_hcm_context=>ty_t_pernrs .
26 | DATA mv_task_class_name TYPE string .
27 | DATA mv_package_size TYPE i .
28 |
29 | METHODS error_process
30 | IMPORTING
31 | !io_message_handler TYPE REF TO zif_capi_message_handler .
32 | METHODS results_to_table
33 | IMPORTING
34 | !io_results TYPE REF TO zif_capi_collection
35 | EXPORTING
36 | !et_result TYPE ANY TABLE .
37 | METHODS long_class_name
38 | RETURNING
39 | VALUE(rv_result) TYPE string .
40 | ENDCLASS.
41 |
42 |
43 |
44 | CLASS ZCL_CAPI_FACADE_HCM IMPLEMENTATION.
45 |
46 |
47 | METHOD constructor.
48 |
49 | mo_context = io_context.
50 | mt_pernrs = it_pernrs.
51 | mv_task_class_name = iv_task_class_name.
52 | mv_package_size = iv_package_size.
53 |
54 | ENDMETHOD.
55 |
56 |
57 | METHOD error_process.
58 |
59 | DATA lt_message_list TYPE zif_capi_message_handler=>ty_message_list_tab.
60 | DATA ls_error_detail_header LIKE LINE OF lt_message_list.
61 |
62 | FIELD-SYMBOLS LIKE LINE OF lt_message_list.
63 |
64 | FORMAT COLOR 6.
65 |
66 | WRITE / 'Errors occurred when tasks were executed in parallel. The data is inconsistent.'(001).
67 | WRITE / 'Please restart the report.'(002).
68 | WRITE / 'If the error persists after restarting, contact support.'(003).
69 |
70 | FORMAT RESET INTENSIFIED ON.
71 | SKIP.
72 |
73 | WRITE / 'Details of errors:'(004).
74 | ls_error_detail_header-task_name = 'Task name'(005).
75 | ls_error_detail_header-rfcmsg = 'Error description'(006).
76 | WRITE: / ls_error_detail_header-task_name, ls_error_detail_header-rfcmsg.
77 |
78 | lt_message_list = io_message_handler->get_message_list( ).
79 | LOOP AT lt_message_list ASSIGNING .
80 | WRITE: / -task_name, -rfcmsg.
81 | ENDLOOP.
82 |
83 | ENDMETHOD.
84 |
85 |
86 | METHOD execute.
87 |
88 | DATA lv_pos_till TYPE i.
89 | DATA lv_number_of_pernrs TYPE i.
90 | DATA lt_pernrs LIKE mt_pernrs.
91 | DATA lt_pernrs_part LIKE mt_pernrs.
92 | DATA lv_long_class_name TYPE string.
93 |
94 | DATA lo_tasks TYPE REF TO zcl_capi_collection.
95 | DATA lo_task TYPE REF TO zcl_capi_facade_hcm_abstr_task.
96 | DATA lo_executor TYPE REF TO zif_capi_executor_service.
97 | DATA lo_message_handler TYPE REF TO zcl_capi_message_handler.
98 | DATA lo_results TYPE REF TO zif_capi_collection.
99 |
100 | DATA: lv_max_no_of_tasks TYPE i.
101 |
102 | " The execute( ) method is an implementation of the Facade structural pattern.
103 | " It is designed to simplify the parallelization process and use the Abap Concurrency API.
104 |
105 | CLEAR et_result.
106 |
107 | lv_long_class_name = long_class_name( ).
108 | lt_pernrs = mt_pernrs.
109 |
110 | CREATE OBJECT lo_tasks.
111 |
112 | lv_number_of_pernrs = lines( lt_pernrs ).
113 |
114 | " Divide personnel numbers into parts for each task
115 | DO.
116 | " Out of personnel numbers?
117 | IF lv_number_of_pernrs IS INITIAL.
118 | EXIT. " Yes
119 | ENDIF.
120 |
121 | IF lv_number_of_pernrs < mv_package_size.
122 | lv_pos_till = lv_number_of_pernrs.
123 | ELSE.
124 | lv_pos_till = mv_package_size.
125 | ENDIF.
126 |
127 | APPEND LINES OF lt_pernrs FROM 1 TO lv_pos_till TO lt_pernrs_part.
128 | DELETE lt_pernrs FROM 1 TO lv_pos_till.
129 |
130 | TRY.
131 | mo_context->zif_capi_facade_hcm_context~set_pernrs( lt_pernrs_part ).
132 |
133 | CREATE OBJECT lo_task TYPE (lv_long_class_name)
134 | EXPORTING
135 | io_context = mo_context.
136 |
137 | lo_tasks->zif_capi_collection~add( lo_task ).
138 |
139 | CATCH cx_root.
140 | MESSAGE 'The task object could not be created'(000) TYPE 'E'.
141 | ENDTRY.
142 |
143 | lv_number_of_pernrs = lines( lt_pernrs ).
144 | CLEAR lt_pernrs_part.
145 | ENDDO.
146 |
147 | CREATE OBJECT lo_message_handler.
148 | lv_max_no_of_tasks = zcl_capi_thread_pool_executor=>max_no_of_tasks( iv_server_group ).
149 |
150 | lo_executor = zcl_capi_executors=>new_fixed_thread_pool( iv_server_group = iv_server_group
151 | iv_n_threads = lv_max_no_of_tasks
152 | iv_no_resubmission_on_error = abap_false
153 | io_capi_message_handler = lo_message_handler ).
154 | " Let's start the tasks for execution.
155 | lo_results = lo_executor->invoke_all( lo_tasks ).
156 |
157 | IF lo_message_handler->zif_capi_message_handler~has_messages( ) = abap_true.
158 | error_process( lo_message_handler ).
159 | ELSE.
160 | results_to_table( EXPORTING io_results = lo_results
161 | IMPORTING et_result = et_result ).
162 | ENDIF.
163 | ENDMETHOD.
164 |
165 |
166 | METHOD long_class_name.
167 |
168 | DATA lo_class TYPE REF TO cl_oo_class.
169 | DATA lv_class_name TYPE seoclsname.
170 |
171 | " This is a global class?
172 | TRY.
173 | lv_class_name = mv_task_class_name.
174 | lo_class ?= cl_oo_class=>get_instance( lv_class_name ).
175 |
176 | " Yes
177 | rv_result = mv_task_class_name.
178 |
179 | CATCH cx_root.
180 | " Nope
181 | CONCATENATE '\' 'PROGRAM=' sy-cprog '\CLASS=' mv_task_class_name INTO rv_result.
182 | ENDTRY.
183 |
184 | ENDMETHOD.
185 |
186 |
187 | METHOD results_to_table.
188 |
189 | DATA lo_data TYPE REF TO data.
190 | DATA lo_results_iterator TYPE REF TO zif_capi_iterator.
191 | DATA lo_result TYPE REF TO zif_capi_facade_hcm_result.
192 |
193 | FIELD-SYMBOLS TYPE ANY TABLE.
194 |
195 | CLEAR et_result.
196 |
197 | lo_results_iterator = io_results->get_iterator( ).
198 |
199 | CREATE DATA lo_data LIKE et_result.
200 | ASSIGN lo_data->* TO .
201 |
202 | IF IS ASSIGNED.
203 | WHILE lo_results_iterator->has_next( ) = abap_true.
204 |
205 | lo_result ?= lo_results_iterator->next( ).
206 | CLEAR .
207 | lo_result->get( IMPORTING et_result = ).
208 | INSERT LINES OF INTO TABLE et_result.
209 |
210 | ENDWHILE.
211 | ENDIF.
212 |
213 | ENDMETHOD.
214 | ENDCLASS.
215 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/zcl_capi_facade_hcm.clas.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCL_CAPI_FACADE_HCM
7 | E
8 | Facade HCM
9 | 1
10 | X
11 | X
12 | X
13 |
14 |
15 |
16 | I
17 | 000
18 | The task object could not be created
19 | 72
20 |
21 |
22 | I
23 | 001
24 | Errors occurred when tasks were executed in parallel. The data is inconsistent.
25 | 132
26 |
27 |
28 | I
29 | 002
30 | Please restart the report.
31 | 52
32 |
33 |
34 | I
35 | 003
36 | If the error persists after restarting, contact support.
37 | 112
38 |
39 |
40 | I
41 | 004
42 | Details of errors:
43 | 28
44 |
45 |
46 | I
47 | 005
48 | Task name
49 | 19
50 |
51 |
52 | I
53 | 006
54 | Error description
55 | 27
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/zcl_capi_facade_hcm_abstr_cntx.clas.abap:
--------------------------------------------------------------------------------
1 | CLASS zcl_capi_facade_hcm_abstr_cntx DEFINITION
2 | PUBLIC
3 | ABSTRACT
4 | CREATE PUBLIC .
5 |
6 | PUBLIC SECTION.
7 |
8 | INTERFACES zif_capi_facade_hcm_context .
9 | PROTECTED SECTION.
10 |
11 | DATA mt_pernrs TYPE zif_capi_facade_hcm_context=>ty_t_pernrs .
12 | PRIVATE SECTION.
13 | ENDCLASS.
14 |
15 |
16 |
17 | CLASS ZCL_CAPI_FACADE_HCM_ABSTR_CNTX IMPLEMENTATION.
18 |
19 |
20 | METHOD zif_capi_facade_hcm_context~get_pernrs.
21 | rt_pernrs = mt_pernrs.
22 | ENDMETHOD.
23 |
24 |
25 | METHOD zif_capi_facade_hcm_context~set_pernrs.
26 | mt_pernrs = it_pernrs.
27 | ENDMETHOD.
28 | ENDCLASS.
29 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/zcl_capi_facade_hcm_abstr_cntx.clas.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCL_CAPI_FACADE_HCM_ABSTR_CNTX
7 | E
8 | Abstract HCM Context
9 | 1
10 | X
11 | X
12 | X
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/zcl_capi_facade_hcm_abstr_task.clas.abap:
--------------------------------------------------------------------------------
1 | CLASS zcl_capi_facade_hcm_abstr_task DEFINITION
2 | PUBLIC
3 | INHERITING FROM zcl_capi_abstract_task
4 | ABSTRACT
5 | CREATE PUBLIC .
6 |
7 | PUBLIC SECTION.
8 |
9 | METHODS constructor
10 | IMPORTING
11 | !iv_id TYPE guid_32 OPTIONAL
12 | !iv_name TYPE string OPTIONAL
13 | !io_context TYPE REF TO zcl_capi_facade_hcm_abstr_cntx .
14 | PROTECTED SECTION.
15 |
16 | DATA mt_pernrs TYPE zif_capi_facade_hcm_context=>ty_t_pernrs .
17 | PRIVATE SECTION.
18 | ENDCLASS.
19 |
20 |
21 |
22 | CLASS ZCL_CAPI_FACADE_HCM_ABSTR_TASK IMPLEMENTATION.
23 |
24 |
25 | METHOD constructor.
26 |
27 | super->constructor( iv_id = iv_id
28 | iv_name = iv_name ).
29 | mt_pernrs = io_context->zif_capi_facade_hcm_context~get_pernrs( ).
30 |
31 | ENDMETHOD.
32 | ENDCLASS.
33 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/zcl_capi_facade_hcm_abstr_task.clas.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCL_CAPI_FACADE_HCM_ABSTR_TASK
7 | E
8 | Abscract HCM Task
9 | 1
10 | X
11 | X
12 | X
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/zif_capi_facade_hcm_context.intf.abap:
--------------------------------------------------------------------------------
1 | INTERFACE zif_capi_facade_hcm_context
2 | PUBLIC .
3 |
4 |
5 | TYPES:
6 | BEGIN OF ty_pernrs,
7 | sign TYPE c LENGTH 1,
8 | option TYPE c LENGTH 2,
9 | low TYPE n LENGTH 8,
10 | high TYPE n LENGTH 8,
11 | END OF ty_pernrs .
12 | TYPES:
13 | ty_t_pernrs TYPE STANDARD TABLE OF ty_pernrs WITH DEFAULT KEY .
14 |
15 | METHODS set_pernrs
16 | IMPORTING
17 | !it_pernrs TYPE ty_t_pernrs .
18 | METHODS get_pernrs
19 | RETURNING
20 | VALUE(rt_pernrs) TYPE ty_t_pernrs .
21 | ENDINTERFACE.
22 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/zif_capi_facade_hcm_context.intf.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZIF_CAPI_FACADE_HCM_CONTEXT
7 | E
8 | ZIF_CAPI_FACADE_HCM_CONTEXT
9 | 2
10 | 1
11 | X
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/zif_capi_facade_hcm_result.intf.abap:
--------------------------------------------------------------------------------
1 | INTERFACE zif_capi_facade_hcm_result
2 | PUBLIC .
3 |
4 |
5 | INTERFACES if_serializable_object .
6 |
7 | METHODS get
8 | EXPORTING
9 | VALUE(et_result) TYPE ANY TABLE .
10 | ENDINTERFACE.
11 |
--------------------------------------------------------------------------------
/src/zcapi_facade/zcapi_facade_hcm/zif_capi_facade_hcm_result.intf.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZIF_CAPI_FACADE_HCM_RESULT
7 | E
8 | ZIF_CAPI_FACADE_HCM_RESULT
9 | 2
10 | 1
11 | X
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/zcl_capi_abstract_task.clas.abap:
--------------------------------------------------------------------------------
1 | CLASS zcl_capi_abstract_task DEFINITION
2 | PUBLIC
3 | ABSTRACT
4 | CREATE PUBLIC .
5 |
6 | PUBLIC SECTION.
7 |
8 | INTERFACES zif_capi_callable .
9 | INTERFACES if_serializable_object .
10 | INTERFACES zif_capi_task .
11 |
12 | METHODS constructor
13 | IMPORTING
14 | !iv_id TYPE guid_32 OPTIONAL
15 | !iv_name TYPE string OPTIONAL .
16 | PROTECTED SECTION.
17 |
18 | CLASS-DATA gv_tasks_quantity TYPE i .
19 | DATA mv_id TYPE guid_32 .
20 | DATA mv_name TYPE string .
21 |
22 | METHODS create_task_name .
23 | METHODS create_task_id .
24 | PRIVATE SECTION.
25 | ENDCLASS.
26 |
27 |
28 |
29 | CLASS ZCL_CAPI_ABSTRACT_TASK IMPLEMENTATION.
30 |
31 |
32 | METHOD constructor.
33 |
34 | IF iv_id IS INITIAL.
35 | create_task_id( ).
36 | ELSE.
37 | mv_id = iv_id.
38 | ENDIF.
39 |
40 | IF iv_name IS INITIAL.
41 | create_task_name( ).
42 | ELSE.
43 | mv_name = iv_name.
44 | ENDIF.
45 |
46 | ENDMETHOD.
47 |
48 |
49 | METHOD create_task_id.
50 |
51 | CALL FUNCTION 'GUID_CREATE'
52 | IMPORTING
53 | ev_guid_32 = mv_id.
54 |
55 | ENDMETHOD.
56 |
57 |
58 | METHOD create_task_name.
59 |
60 | DATA lv_tasks_quantity TYPE string.
61 |
62 | lv_tasks_quantity = gv_tasks_quantity = gv_tasks_quantity + 1.
63 | CONCATENATE 'task_' lv_tasks_quantity INTO mv_name.
64 |
65 | ENDMETHOD.
66 |
67 |
68 | METHOD zif_capi_callable~call.
69 | " This method needs to be overridden (REDEFINITION)
70 | ENDMETHOD.
71 |
72 |
73 | METHOD zif_capi_task~get_id.
74 | rv_result = mv_id.
75 | ENDMETHOD.
76 |
77 |
78 | METHOD zif_capi_task~get_name.
79 | rv_result = mv_name.
80 | ENDMETHOD.
81 |
82 |
83 | METHOD zif_capi_task~get_obj_id.
84 | CONCATENATE mv_id ` ` mv_name INTO rv_result.
85 | ENDMETHOD.
86 | ENDCLASS.
87 |
--------------------------------------------------------------------------------
/src/zcl_capi_abstract_task.clas.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCL_CAPI_ABSTRACT_TASK
7 | E
8 | ZCL_ABSTRACT_TASK
9 | 1
10 | X
11 | X
12 | X
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/zcl_capi_collection.clas.abap:
--------------------------------------------------------------------------------
1 | CLASS zcl_capi_collection DEFINITION
2 | PUBLIC
3 | CREATE PUBLIC .
4 |
5 | PUBLIC SECTION.
6 |
7 | INTERFACES zif_capi_collection .
8 | PROTECTED SECTION.
9 |
10 | DATA mt_collection TYPE STANDARD TABLE OF REF TO object .
11 | PRIVATE SECTION.
12 | ENDCLASS.
13 |
14 |
15 |
16 | CLASS ZCL_CAPI_COLLECTION IMPLEMENTATION.
17 |
18 |
19 | METHOD zif_capi_collection~add.
20 | APPEND ir_object TO mt_collection.
21 | ENDMETHOD.
22 |
23 |
24 | METHOD zif_capi_collection~clear.
25 | CLEAR mt_collection.
26 | ENDMETHOD.
27 |
28 |
29 | METHOD zif_capi_collection~get_item.
30 | READ TABLE mt_collection INTO ro_result INDEX iv_index.
31 | ENDMETHOD.
32 |
33 |
34 | METHOD zif_capi_collection~get_iterator.
35 |
36 | DATA lo_iterator TYPE REF TO zcl_capi_iterator.
37 |
38 | CREATE OBJECT lo_iterator
39 | EXPORTING
40 | ir_collection = me.
41 |
42 | ro_result = lo_iterator.
43 |
44 | ENDMETHOD.
45 |
46 |
47 | METHOD zif_capi_collection~is_empty.
48 |
49 | DATA lv_lines TYPE i.
50 |
51 | lv_lines = lines( mt_collection ).
52 |
53 | IF lv_lines = 0.
54 | rv_result = abap_true.
55 | ENDIF.
56 |
57 | ENDMETHOD.
58 |
59 |
60 | METHOD zif_capi_collection~remove.
61 | DELETE TABLE mt_collection FROM ir_item.
62 | ENDMETHOD.
63 |
64 |
65 | METHOD zif_capi_collection~remove_index.
66 | DELETE mt_collection INDEX iv_index.
67 | ENDMETHOD.
68 |
69 |
70 | METHOD zif_capi_collection~size.
71 | rv_result = lines( mt_collection ).
72 | ENDMETHOD.
73 | ENDCLASS.
74 |
--------------------------------------------------------------------------------
/src/zcl_capi_collection.clas.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCL_CAPI_COLLECTION
7 | E
8 | ZCL_COLLECTION
9 | 1
10 | X
11 | X
12 | X
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/zcl_capi_executors.clas.abap:
--------------------------------------------------------------------------------
1 | CLASS zcl_capi_executors DEFINITION
2 | PUBLIC
3 | CREATE PUBLIC .
4 |
5 | PUBLIC SECTION.
6 |
7 | CLASS-METHODS new_fixed_thread_pool
8 | IMPORTING
9 | !iv_server_group TYPE rfcgr
10 | !iv_n_threads TYPE i DEFAULT 10
11 | !iv_no_resubmission_on_error TYPE boole_d DEFAULT abap_true
12 | !io_capi_message_handler TYPE REF TO zif_capi_message_handler OPTIONAL
13 | RETURNING
14 | VALUE(ro_result) TYPE REF TO zcl_capi_thread_pool_executor .
15 | PROTECTED SECTION.
16 | PRIVATE SECTION.
17 | ENDCLASS.
18 |
19 |
20 |
21 | CLASS ZCL_CAPI_EXECUTORS IMPLEMENTATION.
22 |
23 |
24 | METHOD new_fixed_thread_pool.
25 |
26 | CREATE OBJECT ro_result
27 | EXPORTING
28 | iv_server_group = iv_server_group
29 | iv_n_threads = iv_n_threads
30 | iv_no_resubmission_on_error = iv_no_resubmission_on_error
31 | io_capi_message_handler = io_capi_message_handler.
32 |
33 | ENDMETHOD.
34 | ENDCLASS.
35 |
--------------------------------------------------------------------------------
/src/zcl_capi_executors.clas.testclasses.abap:
--------------------------------------------------------------------------------
1 |
2 | CLASS ltc_capi_executors DEFINITION FOR TESTING
3 | DURATION SHORT
4 | RISK LEVEL HARMLESS.
5 |
6 | PRIVATE SECTION.
7 | DATA mo_cut TYPE REF TO zcl_capi_executors. "class under test
8 |
9 | METHODS setup.
10 | METHODS teardown.
11 | METHODS new_fixed_thread_pool FOR TESTING.
12 | ENDCLASS. "ltc_Capi_Executors
13 |
14 |
15 | CLASS ltc_capi_executors IMPLEMENTATION.
16 |
17 | METHOD setup.
18 |
19 | ENDMETHOD.
20 |
21 |
22 | METHOD teardown.
23 |
24 | ENDMETHOD.
25 |
26 |
27 | METHOD new_fixed_thread_pool.
28 |
29 | DATA lo_capi_mhandler TYPE REF TO zcl_capi_message_handler.
30 | DATA lo_capi_exec TYPE REF TO zcl_capi_thread_pool_executor.
31 |
32 | CREATE OBJECT lo_capi_mhandler.
33 |
34 | lo_capi_exec = zcl_capi_executors=>new_fixed_thread_pool( iv_server_group = 'parallel_generators'
35 | io_capi_message_handler = lo_capi_mhandler ).
36 |
37 | IF lo_capi_exec IS NOT BOUND.
38 | cl_aunit_assert=>fail( msg = 'Testing value lo_Capi_Thread_Pool_Executor' ).
39 | ENDIF.
40 |
41 | ENDMETHOD.
42 |
43 | ENDCLASS.
44 |
--------------------------------------------------------------------------------
/src/zcl_capi_executors.clas.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCL_CAPI_EXECUTORS
7 | E
8 | ZCL_EXECUTOR_SERVICE
9 | 1
10 | X
11 | X
12 | X
13 | X
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/zcl_capi_iterator.clas.abap:
--------------------------------------------------------------------------------
1 | CLASS zcl_capi_iterator DEFINITION
2 | PUBLIC
3 | CREATE PUBLIC .
4 |
5 | PUBLIC SECTION.
6 |
7 | INTERFACES zif_capi_iterator .
8 |
9 | METHODS constructor
10 | IMPORTING
11 | !ir_collection TYPE REF TO zif_capi_collection .
12 | PROTECTED SECTION.
13 | PRIVATE SECTION.
14 |
15 | DATA mr_collection TYPE REF TO zif_capi_collection .
16 | DATA mv_index TYPE i VALUE 0.
17 | ENDCLASS.
18 |
19 |
20 |
21 | CLASS ZCL_CAPI_ITERATOR IMPLEMENTATION.
22 |
23 |
24 | METHOD constructor.
25 | mr_collection = ir_collection.
26 | ENDMETHOD.
27 |
28 |
29 | METHOD zif_capi_iterator~current.
30 |
31 | mv_index = mv_index + 1.
32 | ro_result = mr_collection->get_item( mv_index ).
33 |
34 | ENDMETHOD.
35 |
36 |
37 | METHOD zif_capi_iterator~first.
38 |
39 | mv_index = mv_index + 1.
40 | ro_result = mr_collection->get_item( mv_index ).
41 |
42 | ENDMETHOD.
43 |
44 |
45 | METHOD zif_capi_iterator~get_index.
46 | rv_result = mv_index.
47 | ENDMETHOD.
48 |
49 |
50 | METHOD zif_capi_iterator~has_next.
51 |
52 | IF mv_index < mr_collection->size( ).
53 | rv_result = abap_true.
54 | ELSE.
55 | rv_result = abap_false.
56 | ENDIF.
57 |
58 | ENDMETHOD.
59 |
60 |
61 | METHOD zif_capi_iterator~last.
62 |
63 | mv_index = mr_collection->size( ).
64 | ro_result = mr_collection->get_item( mv_index ).
65 |
66 | ENDMETHOD.
67 |
68 |
69 | METHOD zif_capi_iterator~next.
70 |
71 | mv_index = mv_index + 1.
72 | ro_result = mr_collection->get_item( mv_index ).
73 |
74 | ENDMETHOD.
75 | ENDCLASS.
76 |
--------------------------------------------------------------------------------
/src/zcl_capi_iterator.clas.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCL_CAPI_ITERATOR
7 | E
8 | ZCL_ITERATOR
9 | 1
10 | X
11 | X
12 | X
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/zcl_capi_message_handler.clas.abap:
--------------------------------------------------------------------------------
1 | CLASS zcl_capi_message_handler DEFINITION
2 | PUBLIC
3 | CREATE PUBLIC .
4 |
5 | PUBLIC SECTION.
6 |
7 | INTERFACES zif_capi_message_handler .
8 | PROTECTED SECTION.
9 | PRIVATE SECTION.
10 |
11 | DATA mt_message_list TYPE zif_capi_message_handler~ty_message_list_tab .
12 | ENDCLASS.
13 |
14 |
15 |
16 | CLASS ZCL_CAPI_MESSAGE_HANDLER IMPLEMENTATION.
17 |
18 |
19 | METHOD zif_capi_message_handler~add_message.
20 |
21 | DATA ls_message_list LIKE LINE OF mt_message_list.
22 |
23 | ls_message_list-task_id = iv_task_id.
24 | ls_message_list-task_name = iv_task_name.
25 | ls_message_list-rfcsubrc = iv_rfcsubrc.
26 | ls_message_list-rfcmsg = iv_rfcmsg.
27 |
28 | APPEND ls_message_list TO mt_message_list.
29 |
30 | ENDMETHOD.
31 |
32 |
33 | METHOD zif_capi_message_handler~get_message_list.
34 | rt_result = mt_message_list.
35 | ENDMETHOD.
36 |
37 |
38 | METHOD zif_capi_message_handler~has_messages.
39 |
40 | IF lines( mt_message_list ) > 0.
41 | rv_result = abap_true.
42 | ELSE.
43 | rv_result = abap_false.
44 | ENDIF.
45 |
46 | ENDMETHOD.
47 | ENDCLASS.
48 |
--------------------------------------------------------------------------------
/src/zcl_capi_message_handler.clas.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCL_CAPI_MESSAGE_HANDLER
7 | E
8 | ZCL_MESSAGE_HANDLER
9 | 1
10 | X
11 | X
12 | X
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/zcl_capi_spta_gateway.clas.abap:
--------------------------------------------------------------------------------
1 | CLASS zcl_capi_spta_gateway DEFINITION
2 | PUBLIC
3 | CREATE PUBLIC .
4 |
5 | PUBLIC SECTION.
6 |
7 | DATA mo_tasks TYPE REF TO zif_capi_collection .
8 | DATA mv_no_resubmission_on_error TYPE boole_d .
9 | DATA mo_capi_message_handler TYPE REF TO zif_capi_message_handler .
10 | DATA mo_results TYPE REF TO zif_capi_collection .
11 | DATA mo_tasks_iterator TYPE REF TO zif_capi_iterator .
12 |
13 | CLASS-METHODS serialize_result
14 | IMPORTING
15 | !io_result TYPE REF TO if_serializable_object
16 | RETURNING
17 | VALUE(rv_result) TYPE xstring .
18 | CLASS-METHODS serialize_task
19 | IMPORTING
20 | !io_task TYPE REF TO zif_capi_task
21 | RETURNING
22 | VALUE(rv_result) TYPE xstring .
23 | CLASS-METHODS deserialize_result
24 | IMPORTING
25 | !iv_result TYPE xstring
26 | RETURNING
27 | VALUE(ro_result) TYPE REF TO if_serializable_object .
28 | CLASS-METHODS deserialize_task
29 | IMPORTING
30 | !iv_task TYPE xstring
31 | RETURNING
32 | VALUE(ro_result) TYPE REF TO zif_capi_task .
33 | METHODS constructor
34 | IMPORTING
35 | !io_tasks TYPE REF TO zif_capi_collection
36 | !iv_no_resubmission_on_error TYPE boole_d
37 | !io_capi_message_handler TYPE REF TO zif_capi_message_handler .
38 | PROTECTED SECTION.
39 | PRIVATE SECTION.
40 | ENDCLASS.
41 |
42 |
43 |
44 | CLASS ZCL_CAPI_SPTA_GATEWAY IMPLEMENTATION.
45 |
46 |
47 | METHOD constructor.
48 |
49 | mo_tasks = io_tasks.
50 | mo_tasks_iterator = mo_tasks->get_iterator( ).
51 | mv_no_resubmission_on_error = iv_no_resubmission_on_error.
52 | mo_capi_message_handler = io_capi_message_handler.
53 |
54 | CREATE OBJECT mo_results TYPE zcl_capi_collection.
55 |
56 | ENDMETHOD.
57 |
58 |
59 | METHOD deserialize_result.
60 |
61 | CALL TRANSFORMATION id_indent
62 | SOURCE XML iv_result
63 | RESULT obj = ro_result.
64 |
65 | ENDMETHOD.
66 |
67 |
68 | METHOD deserialize_task.
69 |
70 | CALL TRANSFORMATION id_indent
71 | SOURCE XML iv_task
72 | RESULT obj = ro_result.
73 |
74 | ENDMETHOD.
75 |
76 |
77 | METHOD serialize_result.
78 |
79 | CALL TRANSFORMATION id_indent
80 | SOURCE obj = io_result
81 | RESULT XML rv_result.
82 |
83 | ENDMETHOD.
84 |
85 |
86 | METHOD serialize_task.
87 |
88 | CALL TRANSFORMATION id_indent
89 | SOURCE obj = io_task
90 | RESULT XML rv_result.
91 |
92 | ENDMETHOD.
93 | ENDCLASS.
94 |
--------------------------------------------------------------------------------
/src/zcl_capi_spta_gateway.clas.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCL_CAPI_SPTA_GATEWAY
7 | E
8 | ZCL_SPTA_GATEWAY
9 | 1
10 | X
11 | X
12 | X
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/zcl_capi_thread_pool_executor.clas.abap:
--------------------------------------------------------------------------------
1 | CLASS zcl_capi_thread_pool_executor DEFINITION
2 | PUBLIC
3 | CREATE PUBLIC .
4 |
5 | PUBLIC SECTION.
6 |
7 | INTERFACES zif_capi_executor_service .
8 |
9 | METHODS constructor
10 | IMPORTING
11 | !iv_server_group TYPE rfcgr
12 | !iv_n_threads TYPE i DEFAULT 10
13 | !iv_no_resubmission_on_error TYPE boole_d DEFAULT abap_true
14 | !io_capi_message_handler TYPE REF TO zif_capi_message_handler OPTIONAL .
15 | CLASS-METHODS max_no_of_tasks
16 | IMPORTING
17 | !iv_server_group TYPE rfcgr
18 | RETURNING
19 | VALUE(rv_result) TYPE i .
20 | PROTECTED SECTION.
21 | PRIVATE SECTION.
22 |
23 | DATA mv_server_group TYPE rfcgr .
24 | DATA mv_n_threads TYPE i .
25 | DATA mv_no_resubmission_on_error TYPE boole_d .
26 | DATA mo_capi_message_handler TYPE REF TO zif_capi_message_handler .
27 | ENDCLASS.
28 |
29 |
30 |
31 | CLASS ZCL_CAPI_THREAD_POOL_EXECUTOR IMPLEMENTATION.
32 |
33 |
34 | METHOD constructor.
35 |
36 | mv_server_group = iv_server_group.
37 | mv_n_threads = iv_n_threads.
38 | mv_no_resubmission_on_error = iv_no_resubmission_on_error.
39 |
40 | IF io_capi_message_handler IS BOUND.
41 | mo_capi_message_handler = io_capi_message_handler.
42 | ELSE.
43 | CREATE OBJECT mo_capi_message_handler TYPE zcl_capi_message_handler.
44 | ENDIF.
45 |
46 | ENDMETHOD.
47 |
48 |
49 | METHOD max_no_of_tasks.
50 |
51 | DATA lv_free_pbt_wps TYPE i.
52 |
53 | CALL FUNCTION 'SPBT_INITIALIZE'
54 | EXPORTING
55 | group_name = iv_server_group
56 | IMPORTING
57 | free_pbt_wps = lv_free_pbt_wps
58 | EXCEPTIONS
59 | invalid_group_name = 1
60 | internal_error = 2
61 | pbt_env_already_initialized = 3
62 | currently_no_resources_avail = 4
63 | no_pbt_resources_found = 5
64 | cant_init_different_pbt_groups = 6
65 | OTHERS = 7.
66 | IF sy-subrc = 0.
67 | " We take not all processes.
68 | " We take only 40% of all processes.
69 | " The percentage was chosen experimentally.
70 | rv_result = lv_free_pbt_wps * 40 / 100.
71 | ELSE.
72 | rv_result = 5.
73 | ENDIF.
74 |
75 | ENDMETHOD.
76 |
77 |
78 | METHOD zif_capi_executor_service~invoke_all.
79 |
80 | DATA lo_capi_spta_gateway TYPE REF TO zcl_capi_spta_gateway.
81 | DATA lo_tasks TYPE REF TO zcl_capi_collection.
82 |
83 | lo_tasks ?= io_tasks.
84 |
85 | CREATE OBJECT lo_capi_spta_gateway
86 | EXPORTING
87 | io_tasks = lo_tasks
88 | iv_no_resubmission_on_error = mv_no_resubmission_on_error
89 | io_capi_message_handler = mo_capi_message_handler.
90 |
91 | CALL FUNCTION 'SPTA_PARA_PROCESS_START_2'
92 | EXPORTING
93 | server_group = mv_server_group
94 | max_no_of_tasks = mv_n_threads
95 | before_rfc_callback_form = 'BEFORE_RFC'
96 | in_rfc_callback_form = 'IN_RFC'
97 | after_rfc_callback_form = 'AFTER_RFC'
98 | callback_prog = 'ZCONCURRENCY_API'
99 | CHANGING
100 | user_param = lo_capi_spta_gateway
101 | EXCEPTIONS
102 | invalid_server_group = 1
103 | no_resources_available = 2
104 | OTHERS = 3.
105 | IF sy-subrc = 0.
106 | ro_result ?= lo_capi_spta_gateway->mo_results.
107 | ELSE.
108 | RAISE EXCEPTION TYPE zcx_capi_tasks_invocation
109 | EXPORTING
110 | textid = zcx_capi_tasks_invocation=>error_message
111 | server_group = mv_server_group.
112 | ENDIF.
113 |
114 | ENDMETHOD.
115 | ENDCLASS.
116 |
--------------------------------------------------------------------------------
/src/zcl_capi_thread_pool_executor.clas.testclasses.abap:
--------------------------------------------------------------------------------
1 |
2 | CLASS ltc_capi_thread_pool_executor DEFINITION FOR TESTING
3 | DURATION SHORT
4 | RISK LEVEL HARMLESS
5 | FINAL.
6 |
7 | PRIVATE SECTION.
8 | DATA mo_cut TYPE REF TO zcl_capi_thread_pool_executor. "class under test
9 |
10 | CLASS-METHODS class_setup.
11 | CLASS-METHODS class_teardown.
12 | METHODS setup.
13 | METHODS teardown.
14 | METHODS invoke_all FOR TESTING.
15 | ENDCLASS. "ltc_Capi_Thread_Pool_Executor
16 |
17 |
18 | CLASS ltc_capi_thread_pool_executor IMPLEMENTATION.
19 |
20 | METHOD class_setup.
21 |
22 | ENDMETHOD.
23 |
24 |
25 | METHOD class_teardown.
26 |
27 | ENDMETHOD.
28 |
29 |
30 | METHOD setup.
31 |
32 | DATA lo_capi_message_handler TYPE REF TO zif_capi_message_handler.
33 |
34 | mo_cut = zcl_capi_executors=>new_fixed_thread_pool( iv_server_group = 'parallel_generators'
35 | io_capi_message_handler = lo_capi_message_handler ).
36 | ENDMETHOD.
37 |
38 |
39 | METHOD teardown.
40 |
41 | ENDMETHOD.
42 |
43 |
44 | METHOD invoke_all.
45 |
46 | DATA lo_tasks TYPE REF TO zcl_capi_collection.
47 | DATA lo_results TYPE REF TO zif_capi_collection.
48 | DATA lo_capi_tasks_invocation TYPE REF TO zcx_capi_tasks_invocation.
49 | DATA lv_message_text TYPE string.
50 |
51 | CREATE OBJECT lo_tasks.
52 |
53 | TRY.
54 | lo_results = mo_cut->zif_capi_executor_service~invoke_all( lo_tasks ).
55 |
56 | IF lo_results IS NOT BOUND.
57 | cl_aunit_assert=>fail( msg = 'Testing invoke_all' ).
58 | ENDIF.
59 | CATCH zcx_capi_tasks_invocation INTO lo_capi_tasks_invocation.
60 | lv_message_text = lo_capi_tasks_invocation->get_text( ).
61 | cl_aunit_assert=>fail( msg = lv_message_text ).
62 | ENDTRY.
63 |
64 | ENDMETHOD.
65 |
66 | ENDCLASS.
67 |
--------------------------------------------------------------------------------
/src/zcl_capi_thread_pool_executor.clas.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCL_CAPI_THREAD_POOL_EXECUTOR
7 | E
8 | ZCL_CAPI_THREAD_POOL_EXECUTOR
9 | 1
10 | X
11 | X
12 | X
13 | X
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/zconcurrency_api.prog.abap:
--------------------------------------------------------------------------------
1 | *&---------------------------------------------------------------------*
2 | *& Report ZCONCURRENCY_API
3 | *&---------------------------------------------------------------------*
4 | *&
5 | *&---------------------------------------------------------------------*
6 | REPORT zconcurrency_api.
7 |
8 | TYPE-POOLS spta.
9 |
10 | *&---------------------------------------------------------------------*
11 | *& Form before_rfc
12 | *&---------------------------------------------------------------------*
13 | FORM before_rfc USING is_before_rfc_imp TYPE spta_t_before_rfc_imp
14 | CHANGING cs_before_rfc_exp TYPE spta_t_before_rfc_exp
15 | ct_rfcdata TYPE spta_t_indxtab
16 | ct_failed_objects TYPE spta_t_failed_objects
17 | ct_objects_in_process TYPE spta_t_objects_in_process
18 | co_capi_spta_gateway TYPE REF TO zcl_capi_spta_gateway.
19 |
20 | DATA lo_task TYPE REF TO zif_capi_task.
21 | DATA lv_task TYPE xstring.
22 | DATA ls_objects_in_process LIKE LINE OF ct_objects_in_process.
23 | DATA lv_task_id TYPE guid_32.
24 | DATA lv_task_name TYPE c LENGTH 18.
25 |
26 | IF ct_failed_objects[] IS NOT INITIAL.
27 | PERFORM process_failed_objects CHANGING cs_before_rfc_exp
28 | ct_rfcdata[]
29 | ct_failed_objects[]
30 | ct_objects_in_process[]
31 | co_capi_spta_gateway.
32 | RETURN.
33 | ENDIF.
34 |
35 | IF co_capi_spta_gateway->mo_tasks_iterator->has_next( ) = abap_true.
36 |
37 | lo_task ?= co_capi_spta_gateway->mo_tasks_iterator->next( ).
38 | lv_task = zcl_capi_spta_gateway=>serialize_task( lo_task ).
39 |
40 | CALL FUNCTION 'SPTA_INDX_PACKAGE_ENCODE'
41 | EXPORTING
42 | data = lv_task
43 | IMPORTING
44 | indxtab = ct_rfcdata.
45 |
46 | ls_objects_in_process-obj_id = lo_task->get_obj_id( ).
47 | APPEND ls_objects_in_process TO ct_objects_in_process[].
48 |
49 | cs_before_rfc_exp-start_rfc = abap_true.
50 | ELSE.
51 | cs_before_rfc_exp-start_rfc = space.
52 | ENDIF.
53 |
54 | ENDFORM.
55 |
56 | *&---------------------------------------------------------------------*
57 | *& Form in_rfc
58 | *&---------------------------------------------------------------------*
59 | FORM in_rfc USING is_in_rfc_imp TYPE spta_t_in_rfc_imp
60 | CHANGING cs_in_rfc_exp TYPE spta_t_in_rfc_exp
61 | ct_rfcdata TYPE spta_t_indxtab.
62 |
63 | DATA lv_task TYPE xstring.
64 | DATA lo_task TYPE REF TO zif_capi_task.
65 | DATA lo_result TYPE REF TO if_serializable_object.
66 | DATA lv_result TYPE xstring.
67 |
68 | SET UPDATE TASK LOCAL.
69 |
70 | CALL FUNCTION 'SPTA_INDX_PACKAGE_DECODE'
71 | EXPORTING
72 | indxtab = ct_rfcdata
73 | IMPORTING
74 | data = lv_task.
75 |
76 | lo_task = zcl_capi_spta_gateway=>deserialize_task( lv_task ).
77 | lo_result = lo_task->zif_capi_callable~call( ).
78 | lv_result = zcl_capi_spta_gateway=>serialize_result( lo_result ).
79 |
80 | CALL FUNCTION 'SPTA_INDX_PACKAGE_ENCODE'
81 | EXPORTING
82 | data = lv_result
83 | IMPORTING
84 | indxtab = ct_rfcdata.
85 |
86 | COMMIT WORK.
87 |
88 | ENDFORM.
89 |
90 | *&---------------------------------------------------------------------*
91 | *& Form after_rfc
92 | *&---------------------------------------------------------------------*
93 | FORM after_rfc USING it_rfcdata TYPE spta_t_indxtab
94 | iv_rfcsubrc TYPE sy-subrc
95 | iv_rfcmsg TYPE spta_t_rfcmsg
96 | it_objects_in_process TYPE spta_t_objects_in_process
97 | is_after_rfc_imp TYPE spta_t_after_rfc_imp
98 | CHANGING cs_after_rfc_exp TYPE spta_t_after_rfc_exp
99 | co_capi_spta_gateway TYPE REF TO zcl_capi_spta_gateway.
100 |
101 | CONSTANTS lc_max_task_crash TYPE i VALUE 1.
102 |
103 | DATA lv_result TYPE xstring.
104 | DATA lo_result TYPE REF TO object.
105 | DATA ls_objects_in_process LIKE LINE OF it_objects_in_process.
106 | DATA lv_task_id TYPE guid_32.
107 | DATA lv_task_name TYPE string.
108 | DATA lv_tc_size TYPE i.
109 | DATA lv_rc_size TYPE i.
110 |
111 | IF iv_rfcsubrc IS INITIAL.
112 | " Task completed successfully
113 |
114 | CALL FUNCTION 'SPTA_INDX_PACKAGE_DECODE'
115 | EXPORTING
116 | indxtab = it_rfcdata
117 | IMPORTING
118 | data = lv_result.
119 |
120 | lo_result = zcl_capi_spta_gateway=>deserialize_result( lv_result ).
121 | co_capi_spta_gateway->mo_results->add( lo_result ).
122 |
123 | lv_tc_size = co_capi_spta_gateway->mo_tasks->size( ).
124 | lv_rc_size = co_capi_spta_gateway->mo_results->size( ).
125 |
126 | cl_progress_indicator=>progress_indicate( i_text = '&1% (&2 of &3) of the tasks processed'(001)
127 | i_processed = lv_rc_size
128 | i_total = lv_tc_size
129 | i_output_immediately = abap_true ).
130 | ELSE.
131 |
132 | READ TABLE it_objects_in_process INTO ls_objects_in_process INDEX 1.
133 | IF sy-subrc = 0.
134 | lv_task_id = ls_objects_in_process-obj_id(32).
135 | lv_task_name = ls_objects_in_process-obj_id+32(18).
136 | co_capi_spta_gateway->mo_capi_message_handler->add_message( iv_task_id = lv_task_id
137 | iv_task_name = lv_task_name
138 | iv_rfcsubrc = iv_rfcsubrc
139 | iv_rfcmsg = iv_rfcmsg ).
140 |
141 | IF ls_objects_in_process-fail_count = lc_max_task_crash.
142 | " If the task has already crashed, and now it has crashed a second time,
143 | " we will not restart it
144 | cs_after_rfc_exp-no_resubmission_on_error = abap_true.
145 | ELSE.
146 | cs_after_rfc_exp-no_resubmission_on_error = co_capi_spta_gateway->mv_no_resubmission_on_error.
147 | ENDIF.
148 |
149 | ENDIF.
150 |
151 | ENDIF.
152 |
153 | ENDFORM.
154 |
155 | *&---------------------------------------------------------------------*
156 | *& Form process_failed_objects
157 | *&---------------------------------------------------------------------*
158 | FORM process_failed_objects CHANGING cs_before_rfc_exp TYPE spta_t_before_rfc_exp
159 | ct_rfcdata TYPE spta_t_indxtab
160 | ct_failed_objects TYPE spta_t_failed_objects
161 | ct_objects_in_process TYPE spta_t_objects_in_process
162 | co_capi_spta_gateway TYPE REF TO zcl_capi_spta_gateway.
163 |
164 | DATA lo_tasks_iterator TYPE REF TO zif_capi_iterator.
165 | DATA lo_task TYPE REF TO zif_capi_task.
166 | DATA lv_task TYPE xstring.
167 | DATA ls_objects_in_process LIKE LINE OF ct_objects_in_process.
168 | DATA lv_task_id TYPE guid_32.
169 | DATA lv_task_name TYPE string.
170 |
171 | FIELD-SYMBOLS LIKE LINE OF ct_failed_objects.
172 |
173 | READ TABLE ct_failed_objects ASSIGNING INDEX 1.
174 | IF IS ASSIGNED.
175 |
176 | lo_tasks_iterator = co_capi_spta_gateway->mo_tasks->get_iterator( ).
177 |
178 | WHILE lo_tasks_iterator->has_next( ) = abap_true.
179 | lo_task ?= lo_tasks_iterator->next( ).
180 |
181 | IF lo_task->get_obj_id( ) = -obj_id.
182 |
183 | lv_task = zcl_capi_spta_gateway=>serialize_task( lo_task ).
184 |
185 | CALL FUNCTION 'SPTA_INDX_PACKAGE_ENCODE'
186 | EXPORTING
187 | data = lv_task
188 | IMPORTING
189 | indxtab = ct_rfcdata.
190 |
191 | ls_objects_in_process-obj_id = -obj_id.
192 | ls_objects_in_process-fail_count = -fail_count + 1.
193 | ls_objects_in_process-last_error = -last_error.
194 |
195 | APPEND ls_objects_in_process TO ct_objects_in_process[].
196 |
197 | CLEAR: ct_failed_objects[], ct_failed_objects.
198 | cs_before_rfc_exp-start_rfc = abap_true.
199 | EXIT.
200 | ENDIF.
201 |
202 | ENDWHILE.
203 |
204 | ENDIF.
205 |
206 | ENDFORM.
207 |
--------------------------------------------------------------------------------
/src/zconcurrency_api.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCONCURRENCY_API
7 | 1
8 | E
9 | X
10 | X
11 |
12 |
13 |
14 | I
15 | 001
16 | &1% (&2 of &3) of the tasks processed
17 | 74
18 |
19 |
20 | R
21 | ZCONCURRENCY_API
22 | 16
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/zconcurrency_api.sots.0800272ae9a21edba8bedd438b158fed_e__0001.txt:
--------------------------------------------------------------------------------
1 | &MSG&
--------------------------------------------------------------------------------
/src/zconcurrency_api.sots.0800272ae9a21edba8bf9e75f40d9082_e__0001.txt:
--------------------------------------------------------------------------------
1 | ;
--------------------------------------------------------------------------------
/src/zconcurrency_api.sots.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 0800272AE9A21EDBA8BEDD438B158FED
9 | E
10 | 1
11 | CA==
12 |
13 |
14 |
15 | 0800272AE9A21EDBA8BEDD438B158FED
16 | E
17 | 0001
18 | X
19 | R
20 |
21 |
22 |
23 |
24 |
25 | 0800272AE9A21EDBA8BF9E75F40D9082
26 | E
27 | 1
28 | CA==
29 |
30 |
31 |
32 | 0800272AE9A21EDBA8BF9E75F40D9082
33 | E
34 | 0001
35 | X
36 | R
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/zconcurrency_api_example.prog.abap:
--------------------------------------------------------------------------------
1 | *&---------------------------------------------------------------------*
2 | *& Report ZCONCURRENCY_API_EXAMPLE
3 | *&---------------------------------------------------------------------*
4 | *&
5 | *&---------------------------------------------------------------------*
6 | REPORT zconcurrency_api_example.
7 |
8 | INCLUDE zconcurrency_api_example_cld.
9 | INCLUDE zconcurrency_api_example_cli.
10 |
11 | END-OF-SELECTION.
12 | lcl_app=>main( ).
13 |
--------------------------------------------------------------------------------
/src/zconcurrency_api_example.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCONCURRENCY_API_EXAMPLE
7 | 1
8 | K
9 | E
10 | X
11 | X
12 |
13 |
14 |
15 | R
16 | Program ZCONCURRENCY_API_EXAMPLE
17 | 32
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/zconcurrency_api_example_cld.prog.abap:
--------------------------------------------------------------------------------
1 | *&---------------------------------------------------------------------*
2 | *& Include ZCONCURRENCY_API_EXAMPLE_CLD
3 | *&---------------------------------------------------------------------*
4 | CLASS lcl_app DEFINITION FINAL.
5 | PUBLIC SECTION.
6 |
7 | CLASS-METHODS main.
8 |
9 | ENDCLASS.
10 | *----------------------------------------------------------------------*
11 | * CLASS lcl_context DEFINITION
12 | *----------------------------------------------------------------------*
13 | *
14 | *----------------------------------------------------------------------*
15 | CLASS lcl_context DEFINITION FINAL.
16 | PUBLIC SECTION.
17 |
18 | INTERFACES if_serializable_object.
19 |
20 | TYPES:
21 | BEGIN OF ty_params,
22 | param TYPE i,
23 | END OF ty_params.
24 |
25 | METHODS:
26 | constructor IMPORTING is_params TYPE ty_params,
27 | get RETURNING VALUE(rs_params) TYPE ty_params.
28 |
29 | PRIVATE SECTION.
30 |
31 | DATA ms_params TYPE ty_params.
32 |
33 | ENDCLASS.
34 | *----------------------------------------------------------------------*
35 | * CLASS lcl_task DEFINITION
36 | *----------------------------------------------------------------------*
37 | *
38 | *----------------------------------------------------------------------*
39 | CLASS lcl_task DEFINITION INHERITING FROM zcl_capi_abstract_task FINAL.
40 | PUBLIC SECTION.
41 |
42 | METHODS:
43 | constructor IMPORTING io_context TYPE REF TO lcl_context,
44 | zif_capi_callable~call REDEFINITION.
45 |
46 | PRIVATE SECTION.
47 |
48 | DATA mo_context TYPE REF TO lcl_context.
49 | DATA mv_res TYPE i.
50 |
51 | ENDCLASS.
52 | *----------------------------------------------------------------------*
53 | * CLASS lcl_result DEFINITION
54 | *----------------------------------------------------------------------*
55 | *
56 | *----------------------------------------------------------------------*
57 | CLASS lcl_result DEFINITION FINAL.
58 | PUBLIC SECTION.
59 |
60 | INTERFACES if_serializable_object.
61 |
62 | METHODS:
63 | constructor IMPORTING iv_param TYPE i
64 | iv_result TYPE i,
65 | get RETURNING VALUE(rv_result) TYPE string.
66 |
67 | PRIVATE SECTION.
68 | DATA mv_param TYPE i.
69 | DATA mv_result TYPE i.
70 |
71 | ENDCLASS.
72 |
--------------------------------------------------------------------------------
/src/zconcurrency_api_example_cld.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCONCURRENCY_API_EXAMPLE_CLD
7 | I
8 | E
9 | X
10 |
11 |
12 |
13 | R
14 | Include ZCONCURRENCY_API_EXAMPLE_CLD
15 | 36
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/zconcurrency_api_example_cli.prog.abap:
--------------------------------------------------------------------------------
1 | *&---------------------------------------------------------------------*
2 | *& Include ZCONCURRENCY_API_EXAMPLE_CLI
3 | *&---------------------------------------------------------------------*
4 | CLASS lcl_app IMPLEMENTATION.
5 | METHOD main.
6 |
7 | CONSTANTS lc_server_group TYPE rfcgr VALUE 'parallel_generators'.
8 |
9 | DATA lo_tasks TYPE REF TO zcl_capi_collection.
10 | DATA lo_task TYPE REF TO lcl_task.
11 | DATA lo_context TYPE REF TO lcl_context.
12 | DATA ls_params TYPE lcl_context=>ty_params.
13 | DATA lo_executor TYPE REF TO zif_capi_executor_service.
14 | DATA lo_message_handler TYPE REF TO zcl_capi_message_handler.
15 | DATA lt_message_list TYPE zif_capi_message_handler=>ty_message_list_tab.
16 | DATA lo_results TYPE REF TO zif_capi_collection.
17 | DATA lo_results_iterator TYPE REF TO zif_capi_iterator.
18 | DATA lo_result TYPE REF TO lcl_result.
19 | DATA lv_result TYPE string.
20 | DATA lo_capi_tasks_invocation TYPE REF TO zcx_capi_tasks_invocation.
21 | DATA lv_message_text TYPE string.
22 | DATA lv_max_no_of_tasks TYPE i.
23 |
24 | FIELD-SYMBOLS LIKE LINE OF lt_message_list.
25 |
26 | * Create collection of tasks
27 | CREATE OBJECT lo_tasks.
28 |
29 | DO 10 TIMES.
30 | ls_params-param = sy-index.
31 |
32 | * Optional object. It contains task parameters
33 | CREATE OBJECT lo_context
34 | EXPORTING
35 | is_params = ls_params.
36 |
37 | CREATE OBJECT lo_task
38 | EXPORTING
39 | io_context = lo_context.
40 |
41 | lo_tasks->zif_capi_collection~add( lo_task ).
42 | ENDDO.
43 |
44 | CREATE OBJECT lo_message_handler.
45 | lv_max_no_of_tasks = zcl_capi_thread_pool_executor=>max_no_of_tasks( lc_server_group ).
46 |
47 | lo_executor = zcl_capi_executors=>new_fixed_thread_pool( iv_server_group = lc_server_group
48 | iv_n_threads = lv_max_no_of_tasks
49 | io_capi_message_handler = lo_message_handler ).
50 | TRY.
51 | lo_results = lo_executor->invoke_all( lo_tasks ).
52 | lo_results_iterator = lo_results->get_iterator( ).
53 |
54 | IF lo_message_handler->zif_capi_message_handler~has_messages( ) = abap_true.
55 |
56 | lt_message_list = lo_message_handler->zif_capi_message_handler~get_message_list( ).
57 |
58 | LOOP AT lt_message_list ASSIGNING .
59 | WRITE: / -task_id,
60 | -task_name,
61 | -rfcsubrc,
62 | -rfcmsg.
63 | ENDLOOP.
64 |
65 | ELSE.
66 |
67 | WHILE lo_results_iterator->has_next( ) = abap_true.
68 | lo_result ?= lo_results_iterator->next( ).
69 | lv_result = lo_result->get( ).
70 | WRITE / lv_result.
71 | ENDWHILE.
72 |
73 | ENDIF.
74 |
75 | CATCH zcx_capi_tasks_invocation INTO lo_capi_tasks_invocation.
76 | lv_message_text = lo_capi_tasks_invocation->get_text( ).
77 | WRITE lv_message_text.
78 | ENDTRY.
79 |
80 | ENDMETHOD.
81 | ENDCLASS.
82 | *----------------------------------------------------------------------*
83 | * CLASS lcl_context IMPLEMENTATION
84 | *----------------------------------------------------------------------*
85 | *
86 | *----------------------------------------------------------------------*
87 | CLASS lcl_context IMPLEMENTATION.
88 | METHOD constructor.
89 | ms_params = is_params.
90 | ENDMETHOD.
91 |
92 | METHOD get.
93 | rs_params = ms_params.
94 | ENDMETHOD.
95 | ENDCLASS.
96 |
97 | *----------------------------------------------------------------------*
98 | * CLASS lcl_task DEFINITION
99 | *----------------------------------------------------------------------*
100 | *
101 | *----------------------------------------------------------------------*
102 | CLASS lcl_task IMPLEMENTATION.
103 | METHOD constructor.
104 |
105 | super->constructor( ).
106 | mo_context = io_context.
107 |
108 | ENDMETHOD.
109 |
110 | METHOD zif_capi_callable~call.
111 |
112 | DATA ls_params TYPE lcl_context=>ty_params.
113 |
114 | ls_params = mo_context->get( ).
115 | mv_res = ls_params-param ** 2.
116 |
117 | CREATE OBJECT ro_result
118 | TYPE
119 | lcl_result
120 | EXPORTING
121 | iv_param = ls_params-param
122 | iv_result = mv_res.
123 |
124 | ENDMETHOD.
125 | ENDCLASS.
126 |
127 | *----------------------------------------------------------------------*
128 | * CLASS lcl_result IMPLEMENTATION
129 | *----------------------------------------------------------------------*
130 | *
131 | *----------------------------------------------------------------------*
132 | CLASS lcl_result IMPLEMENTATION.
133 | METHOD constructor.
134 |
135 | mv_param = iv_param.
136 | mv_result = iv_result.
137 |
138 | ENDMETHOD.
139 |
140 | METHOD get.
141 |
142 | DATA lv_param TYPE string.
143 | DATA lv_result TYPE string.
144 |
145 | lv_param = mv_param.
146 | lv_result = mv_result.
147 |
148 | CONDENSE lv_param.
149 | CONDENSE lv_result.
150 | CONCATENATE lv_param ` -> ` lv_result INTO rv_result.
151 |
152 | ENDMETHOD.
153 | ENDCLASS.
154 |
--------------------------------------------------------------------------------
/src/zconcurrency_api_example_cli.prog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCONCURRENCY_API_EXAMPLE_CLI
7 | I
8 | E
9 | X
10 |
11 |
12 |
13 | R
14 | Include ZCONCURRENCY_API_EXAMPLE_CLI
15 | 36
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/zcx_capi_tasks_invocation.clas.abap:
--------------------------------------------------------------------------------
1 | class ZCX_CAPI_TASKS_INVOCATION definition
2 | public
3 | inheriting from CX_STATIC_CHECK
4 | create public .
5 |
6 | public section.
7 |
8 | interfaces IF_T100_MESSAGE .
9 |
10 | constants:
11 | BEGIN OF error_message,
12 | msgid TYPE symsgid VALUE 'SPTA',
13 | msgno TYPE symsgno VALUE '004',
14 | attr1 TYPE scx_attrname VALUE 'SERVER_GROUP',
15 | attr2 TYPE scx_attrname VALUE '',
16 | attr3 TYPE scx_attrname VALUE '',
17 | attr4 TYPE scx_attrname VALUE '',
18 | END OF error_message .
19 | data SERVER_GROUP type RFCGR .
20 |
21 | methods CONSTRUCTOR
22 | importing
23 | !TEXTID like IF_T100_MESSAGE=>T100KEY optional
24 | !PREVIOUS like PREVIOUS optional
25 | !SERVER_GROUP type RFCGR optional .
26 | protected section.
27 | private section.
28 | ENDCLASS.
29 |
30 |
31 |
32 | CLASS ZCX_CAPI_TASKS_INVOCATION IMPLEMENTATION.
33 |
34 |
35 | method CONSTRUCTOR.
36 | CALL METHOD SUPER->CONSTRUCTOR
37 | EXPORTING
38 | PREVIOUS = PREVIOUS
39 | .
40 | me->SERVER_GROUP = SERVER_GROUP .
41 | clear me->textid.
42 | if textid is initial.
43 | IF_T100_MESSAGE~T100KEY = IF_T100_MESSAGE=>DEFAULT_TEXTID.
44 | else.
45 | IF_T100_MESSAGE~T100KEY = TEXTID.
46 | endif.
47 | endmethod.
48 | ENDCLASS.
49 |
--------------------------------------------------------------------------------
/src/zcx_capi_tasks_invocation.clas.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZCX_CAPI_TASKS_INVOCATION
7 | E
8 | ZCX_CAPI_TASKS_INVOCATION
9 | 40
10 | 1
11 | X
12 | X
13 | X
14 | K
15 |
16 |
17 |
18 |
19 | 0800272AE9A21EDBA8BFAB91EE54D08F
20 | E
21 | 1
22 | CA==
23 |
24 |
25 |
26 | 0800272AE9A21EDBA8BFAB91EE54D08F
27 | E
28 | 0001
29 | X
30 | R
31 | 255
32 |
33 |
34 |
35 |
36 |
37 |
38 | LIMU
39 |
40 | ZCX_CAPI_TASKS_INVOCATION
41 | 0800272AE9A21EDBA8BFAB91EE54D08F
42 | 0001
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/zif_capi_callable.intf.abap:
--------------------------------------------------------------------------------
1 | INTERFACE zif_capi_callable
2 | PUBLIC .
3 |
4 |
5 | METHODS call
6 | RETURNING
7 | VALUE(ro_result) TYPE REF TO if_serializable_object .
8 | ENDINTERFACE.
9 |
--------------------------------------------------------------------------------
/src/zif_capi_callable.intf.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZIF_CAPI_CALLABLE
7 | E
8 | ZIF_CAPI_CALLABLE
9 | 2
10 | 1
11 | X
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/zif_capi_collection.intf.abap:
--------------------------------------------------------------------------------
1 | INTERFACE zif_capi_collection
2 | PUBLIC .
3 |
4 |
5 | METHODS size
6 | RETURNING
7 | VALUE(rv_result) TYPE i .
8 | METHODS is_empty
9 | RETURNING
10 | VALUE(rv_result) TYPE boole_d .
11 | METHODS get_item
12 | IMPORTING
13 | !iv_index TYPE i
14 | RETURNING
15 | VALUE(ro_result) TYPE REF TO object .
16 | METHODS add
17 | IMPORTING
18 | !ir_object TYPE REF TO object .
19 | METHODS remove_index
20 | IMPORTING
21 | !iv_index TYPE i .
22 | METHODS remove
23 | IMPORTING
24 | !ir_item TYPE REF TO object .
25 | METHODS clear .
26 | METHODS get_iterator
27 | RETURNING
28 | VALUE(ro_result) TYPE REF TO zif_capi_iterator .
29 | ENDINTERFACE.
30 |
--------------------------------------------------------------------------------
/src/zif_capi_collection.intf.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZIF_CAPI_COLLECTION
7 | E
8 | ZIF_COLLECTION
9 | 2
10 | 1
11 | X
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/zif_capi_executor_service.intf.abap:
--------------------------------------------------------------------------------
1 | INTERFACE zif_capi_executor_service
2 | PUBLIC .
3 |
4 |
5 | METHODS invoke_all
6 | IMPORTING
7 | !io_tasks TYPE REF TO zif_capi_collection
8 | RETURNING
9 | VALUE(ro_result) TYPE REF TO zif_capi_collection
10 | RAISING
11 | zcx_capi_tasks_invocation .
12 | ENDINTERFACE.
13 |
--------------------------------------------------------------------------------
/src/zif_capi_executor_service.intf.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZIF_CAPI_EXECUTOR_SERVICE
7 | E
8 | ZIF_CAPI_EXECUTOR_SERVICE
9 | 2
10 | 1
11 | X
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/zif_capi_iterator.intf.abap:
--------------------------------------------------------------------------------
1 | INTERFACE zif_capi_iterator
2 | PUBLIC .
3 |
4 |
5 | METHODS get_index
6 | RETURNING
7 | VALUE(rv_result) TYPE i .
8 | METHODS has_next
9 | RETURNING
10 | VALUE(rv_result) TYPE boole_d .
11 | METHODS next
12 | RETURNING
13 | VALUE(ro_result) TYPE REF TO object .
14 | METHODS first
15 | RETURNING
16 | VALUE(ro_result) TYPE REF TO object .
17 | METHODS last
18 | RETURNING
19 | VALUE(ro_result) TYPE REF TO object .
20 | METHODS current
21 | RETURNING
22 | VALUE(ro_result) TYPE REF TO object .
23 | ENDINTERFACE.
24 |
--------------------------------------------------------------------------------
/src/zif_capi_iterator.intf.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZIF_CAPI_ITERATOR
7 | E
8 | ZIF_ITERATOR
9 | 2
10 | 1
11 | X
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/zif_capi_message_handler.intf.abap:
--------------------------------------------------------------------------------
1 | INTERFACE zif_capi_message_handler
2 | PUBLIC .
3 |
4 |
5 | TYPES:
6 | BEGIN OF ty_message_list,
7 | task_id TYPE guid_32,
8 | task_name TYPE string,
9 | rfcsubrc TYPE i,
10 | rfcmsg TYPE spta_t_rfcmsg,
11 | END OF ty_message_list .
12 | TYPES:
13 | ty_message_list_tab TYPE STANDARD TABLE OF ty_message_list WITH KEY task_id .
14 |
15 | METHODS add_message
16 | IMPORTING
17 | !iv_task_id TYPE guid_32
18 | !iv_task_name TYPE string
19 | !iv_rfcsubrc TYPE i
20 | !iv_rfcmsg TYPE spta_t_rfcmsg .
21 | METHODS get_message_list
22 | RETURNING
23 | VALUE(rt_result) TYPE ty_message_list_tab .
24 | METHODS has_messages
25 | RETURNING
26 | VALUE(rv_result) TYPE boole_d .
27 | ENDINTERFACE.
28 |
--------------------------------------------------------------------------------
/src/zif_capi_message_handler.intf.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZIF_CAPI_MESSAGE_HANDLER
7 | E
8 | ZIF_MESSAGE_HANDLER
9 | 2
10 | 1
11 | X
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/zif_capi_task.intf.abap:
--------------------------------------------------------------------------------
1 | INTERFACE zif_capi_task
2 | PUBLIC .
3 |
4 |
5 | INTERFACES if_serializable_object .
6 | INTERFACES zif_capi_callable .
7 |
8 | METHODS get_name
9 | RETURNING
10 | VALUE(rv_result) TYPE string .
11 | METHODS get_id
12 | RETURNING
13 | VALUE(rv_result) TYPE guid_32 .
14 | METHODS get_obj_id
15 | RETURNING
16 | VALUE(rv_result) TYPE string .
17 | ENDINTERFACE.
18 |
--------------------------------------------------------------------------------
/src/zif_capi_task.intf.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ZIF_CAPI_TASK
7 | E
8 | ZIF_TASK
9 | 2
10 | 1
11 | X
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/translations/ru/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | [](https://github.com/victorizbitskiy/zconcurrency_api/blob/main/LICENSE)
4 | 
5 | [](https://abaplint.app/stats/victorizbitskiy/zconcurrency_api)
6 |
7 | Переводы:
8 | - [:uk: In English](https://github.com/victorizbitskiy/zconcurrency_api)
9 |
10 | ## `ABAP Concurrency API`
11 | API для параллельного выполнения, основанный на SPTA Framework.
12 |
13 | `Примечание`: Изначальная идея заключалась в том, чтобы сделать этот API похожим на [Java Concurrency API](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/package-summary.html).
14 | Поэтому было выбрано название `ABAP Concurrency API`. Однако в нашем случае вычисления выполняются не `согласованно`, а `параллельно`.
15 | Для получения более подробной информации, пожалуйста, посмотрите [это](https://wiki.haskell.org/Parallelism_vs._Concurrency) объяснение.
16 |
17 | ---
18 |
19 |
Не забудь щёлкнуть ⭐, если тебе нравится проект!
20 |
21 | ---
22 |
23 | # Оглавление
24 | 1. [Что это такое?](#Что-это-такое)
25 | 2. [Зачем это нужно?](#Зачем-это-нужно)
26 | 3. [Установка](#Установка)
27 | 4. [Использование](#Использование)
28 | 5. [Использование в модуле HCM](#Использование-в-модуле-HCM)
29 | 6. [UML диаграммы](#Диаграммы)
30 | 7. [Зависимости](#Зависимости)
31 | 8. [Ограничения](#Ограничения)
32 | 9. [Как внести свой вклад](#Как-внести-свой-вклад)
33 | 10. [Остались вопросы?](#Остались-вопросы)
34 | 12. [Логотип](#Логотип)
35 |
36 | ## Что это такое?
37 | `ABAP Concurrency API` - это несколько классов, предназначенных для реализации параллельных вычислений.
38 |
39 | ## Зачем это нужно?
40 | Реализация параллельных вычислений в ABAP обычно включает следующие шаги:
41 | 1. Создание RFC ФМ-а
42 | 2. **Реализация** внутри него **бизнес-логики**
43 | 3. Асинхронный вызов RFC ФМ-а в цикле
44 | 4. Ожидание выполнения и **получение результатов работы**
45 |
46 | Если посмотреть на получившийся список, то можно заметить, что по большому счету нас интересует только шаги **`2`** и **`4`**.
47 | Все остальное - это рутинная работа, которая каждый раз занимает время и, потенциально, может быть источником ошибок.
48 |
49 | Чтобы не создавать RFC ФМ каждый раз, когда необходимо выполнить параллельную обработку, можно использовать SPTA Framework, который нам предоставил вендор.
50 | SPTA Framework это хороший инструмент, но интерфейс взаимодействия с ним оставляет желать лучшего. Из-за этого, разработчику приходится прикладывать не малые усилия для того, чтобы реализовать сам процесс распараллеливания.
51 |
52 | Кроме того, написать чистый код, используя непосредственно SPTA Framework тоже не самая простая задача. Нужно быть настоящим ниндзя, чтобы избежать использования глобальных переменных. В конечном итоге, код может получится запутанным и тяжело поддерживаемым.
53 |
54 | `ABAP Concurrency API` позволяет избежать этих проблем. С ним вы можете позволить себе мыслить более абстрактно.
55 | Вам не нужно акцентировать внимание на распараллеливании. Вместо этого, вы можете уделить больше времени бизнес-логике вашего приложения.
56 |
57 | ## Установка
58 | Установка выполняется с помощью [abapGit](http://www.abapgit.org).
59 |
60 | ## Использование
61 | Рассмотрим простую задачу:
62 |
63 | *Необходимо найти квадраты чисел от **`1`** до **`10`***.
64 |
65 | Квадрат каждого из чисел будем искать в отдельной задаче/процессе.
66 | Пример оторван от реального мира, но его достаточно для того, чтобы понять, как работать с API.
67 |
68 | Для начала создадим 3 локальных класса: *Контекст*, *Задача* и *Результат*.
69 | При необходимости вы можете создать глобальные классы.
70 |
71 | 1. **lcl_contex**, объект этого класса будет инкапсулировать параметры задачи.
72 | Использование этого класса не обязательно. Можно обойтись и без него, передав параметры задачи непосредственно в ее конструктор.
73 | Однако, использование отдельного класса, на мой взгляд, предпочтительнее.
74 |
75 |
76 | Посмотреть код...
77 |
78 | ```abap
79 | CLASS lcl_context DEFINITION FINAL.
80 | PUBLIC SECTION.
81 | INTERFACES if_serializable_object.
82 |
83 | TYPES:
84 | BEGIN OF ty_params,
85 | param TYPE i,
86 | END OF ty_params.
87 |
88 | METHODS:
89 | constructor IMPORTING is_params TYPE ty_params,
90 | get RETURNING VALUE(rs_params) TYPE ty_params.
91 |
92 | PRIVATE SECTION.
93 | DATA ms_params TYPE ty_params.
94 | ENDCLASS.
95 |
96 | CLASS lcl_context IMPLEMENTATION.
97 | METHOD constructor.
98 | ms_params = is_params.
99 | ENDMETHOD.
100 |
101 | METHOD get.
102 | rs_params = ms_params.
103 | ENDMETHOD.
104 | ENDCLASS.
105 | ```
106 |
107 |
108 | 2. **lcl_task**, описывает объект *Задача*. Содержит бизнес-логику (в нашем случае возведение числа в степень 2).
109 | Обратите внимание, что класс **lcl_task** наследуется от класса **zcl_capi_abstract_task** и переопределяет метод *zif_capi_callable~call*.
110 |
111 | Посмотреть код...
112 |
113 | ```abap
114 | CLASS lcl_task DEFINITION INHERITING FROM zcl_capi_abstract_task FINAL.
115 | PUBLIC SECTION.
116 |
117 | METHODS:
118 | constructor IMPORTING io_context TYPE REF TO lcl_context,
119 | zif_capi_callable~call REDEFINITION.
120 |
121 | PRIVATE SECTION.
122 | DATA mo_context TYPE REF TO lcl_context.
123 | DATA mv_res TYPE i.
124 | ENDCLASS.
125 |
126 | CLASS lcl_task IMPLEMENTATION.
127 | METHOD constructor.
128 | super->constructor( ).
129 | mo_context = io_context.
130 | ENDMETHOD.
131 |
132 | METHOD zif_capi_callable~call.
133 |
134 | DATA(ls_params) = mo_context->get( ).
135 | mv_res = ls_params-param ** 2.
136 |
137 | ro_result = new lcl_result( iv_param = ls_params-param
138 | iv_result = mv_res ).
139 | ENDMETHOD.
140 | ENDCLASS.
141 | ```
142 |
143 |
144 | 3. **lcl_result** описывает *Результат* выполнения задачи.
145 | Этот класс должен реализовывать интерфейс **if_serializable_object**. В остальном вы можете описать его произвольным образом.
146 |
147 |
148 | Посмотреть код...
149 |
150 | ```abap
151 | CLASS lcl_result DEFINITION FINAL.
152 | PUBLIC SECTION.
153 | INTERFACES if_serializable_object.
154 |
155 | METHODS:
156 | constructor IMPORTING iv_param TYPE i
157 | iv_result TYPE i,
158 | get RETURNING VALUE(rv_result) TYPE string.
159 |
160 | PRIVATE SECTION.
161 | DATA mv_param TYPE i.
162 | DATA mv_result TYPE i.
163 | ENDCLASS.
164 |
165 | CLASS lcl_result IMPLEMENTATION.
166 | METHOD constructor.
167 | mv_param = iv_param.
168 | mv_result = iv_result.
169 | ENDMETHOD.
170 |
171 | METHOD get.
172 | rv_result = |{ mv_param } -> { mv_result }|.
173 | ENDMETHOD.
174 | ENDCLASS.
175 | ```
176 |
177 |
178 |
179 | **Внимание:**
180 | Объекты классов **lcl_task** и **lcl_result** сериализуются/десериализуются в процессе выполнения, поэтому избегайте использования статичных атрибутов.
181 | Статичные атрибуты принадлежат классу, а не объекту. Их содержимое при сериализации/десериализации будет утеряно.
182 |
183 | Итак, объекты *Контекст*, *Задача* и *Результат* описаны.
184 | Теперь посмотрим пример их применения:
185 |
186 |
187 | Посмотреть код...
188 |
189 | ```abap
190 | CONSTANTS lc_server_group TYPE rfcgr VALUE 'parallel_generators'.
191 | DATA lo_result TYPE REF TO lcl_result.
192 |
193 | " Create collection of tasks
194 | DATA(lo_tasks) = NEW zcl_capi_collection( ).
195 |
196 | DO 10 TIMES.
197 |
198 | DATA(lo_context) = NEW lcl_context( VALUE lcl_context=>ty_params( param = sy-index ) ).
199 | DATA(lo_task) = NEW lcl_task( lo_context ).
200 | lo_tasks->zif_capi_collection~add( lo_task ).
201 |
202 | ENDDO.
203 |
204 | DATA(lo_message_handler) = NEW zcl_capi_message_handler( ).
205 | DATA(lv_max_no_of_tasks) = zcl_capi_thread_pool_executor=>max_no_of_tasks( lc_server_group ).
206 |
207 | DATA(lo_executor) = zcl_capi_executors=>new_fixed_thread_pool( iv_server_group = lc_server_group
208 | iv_n_threads = lv_max_no_of_tasks
209 | io_capi_message_handler = lo_message_handler ).
210 | TRY.
211 | DATA(lo_results) = lo_executor->zif_capi_executor_service~invoke_all( lo_tasks ).
212 |
213 | IF lo_message_handler->zif_capi_message_handler~has_messages( ) = abap_false.
214 |
215 | DATA(lo_results_iterator) = lo_results->get_iterator( ).
216 |
217 | WHILE lo_results_iterator->has_next( ).
218 | lo_result ?= lo_results_iterator->next( ).
219 | WRITE / lo_result->get( ).
220 | ENDWHILE.
221 |
222 | ENDIF.
223 |
224 | CATCH zcx_capi_tasks_invocation INTO DATA(lo_capi_tasks_invocation).
225 | WRITE lo_capi_tasks_invocation->get_text( ).
226 | ENDTRY.
227 | ```
228 |
229 |
230 | 1. Сначала создаем *Коллекцию задач* **lo_tasks**
231 | 2. Далее, создаем *Задачу* **lo_task** и добавляем ее в *Коллекцию задач* **lo_tasks**
232 | 3. Создаем *Обработчик сообщений* **lo_message_handler** (опционально)
233 | 4. Теперь мы подошли к наиболее важной части API - к понятию "сервиса-исполнителя". Сервис-исполнитель асинхронно выполняет переданные в него задачи.
234 | В примере мы вызываем статичный метод **zcl_capi_executors=>new_fixed_thread_pool**, который возвращает нам объект **lo_executor** с фиксированным количеством потоков. Метод имеет 4 параметра:
235 |
236 | | Имя параметра | Опционально | Описание |
237 | | :-------------------------- | :-----: | :----------------------------------------------------------- |
238 | | iv_server_group | | группа серверов (tcode: RZ12) |
239 | | iv_max_no_of_tasks | | максимальное количество параллельно выполняющихся задач |
240 | | iv_no_resubmission_on_error | | флаг, "**true**"- не запускать повторно задачу при возникновении ошибке |
241 | | io_capi_message_handler | X | объект, который будет содержать сообщения об ошибках (если они произошли) |
242 |
243 | Объект lo_executor имеет только один интерфейсный метод **zif_capi_executor_service~invoke_all()**, который принимает на вход *Коллекцию задач* и возвращает *Коллекцию результатов* **lo_results** (подход заимствован из **java.util.concurrent.***).
244 |
245 | 5. У *Коллекции результатов* **lo_results** есть итератор, используя который мы легко получаем *Результаты работы* **lo_result** и вызываем у них метод **get( )**.
246 |
247 | В итоге, нам не пришлось создавать RFC ФМ, описывать процесс распараллеливания и т.д.
248 | Все что мы сделали, это описали что собой представляют *Задача* и *Результат*.
249 |
250 | **Результат работы:**
251 |
252 | 
253 |
254 | Рассмотренный пример использования `ABAP Concurrency API` можно найти в отчете **ZCONCURRENCY_API_EXAMPLE**.
255 |
256 | ## Использование в модуле HCM
257 | Для упрощения работы с ABAP Concurrency API в модуле HCM предлагается использовать реализацию структурного паттерна Фасад - пакет ZCAPI_FACADE_HCM. Дополнение инкапсулирует разбиение табельных номеров на пакеты, создание объектов Задача и получение результата.
258 |
259 | Рассмотрим задачу:
260 |
261 | *Необходимо по табельным номерам получить ФИО сотрудников*.
262 |
263 | ФИО сотрудников будем искать в отдельной задаче/процессе.
264 | Для начала все также создадим 3 класса: *Контекст*, *Задача* и *Результат*.
265 |
266 | 1. **lcl_contex**, объект этого класса будет инкапсулировать параметры задачи. Обратите внимание, что класс *lcl_contex* должен быть наследован от абстрактного класса **zcl_capi_facade_hcm_abstr_cntx**. При реализации необходимо переопределить метод *constructor*.
267 |
268 |
269 |
270 | Посмотреть код...
271 |
272 | ```abap
273 | CLASS lcl_context DEFINITION INHERITING FROM zcl_capi_facade_hcm_abstr_cntx FINAL.
274 | PUBLIC SECTION.
275 |
276 | TYPES:
277 | BEGIN OF ty_params,
278 | begda TYPE d,
279 | endda TYPE d,
280 | END OF ty_params.
281 |
282 | METHODS:
283 | constructor IMPORTING is_params TYPE ty_params,
284 | get_params RETURNING VALUE(rs_params) TYPE ty_params.
285 |
286 | PRIVATE SECTION.
287 | DATA ms_params TYPE ty_params.
288 |
289 | ENDCLASS.
290 |
291 | CLASS lcl_context IMPLEMENTATION.
292 | METHOD constructor.
293 | super->constructor( ).
294 | ms_params = is_params.
295 | ENDMETHOD.
296 |
297 | METHOD get_params.
298 | rs_params = ms_params.
299 | ENDMETHOD.
300 | ENDCLASS.
301 | ```
302 |
303 |
304 | 2. **lcl_task**, описывает объект *Задача*. Содержит бизнес-логику (получение ФИО по табельному номеру сотрудника).
305 | Класс **lcl_task** должен быть наследован от класса **zcl_capi_facade_hcm_abstr_task**. Необходимо реализовать метод *constructor* и переопределить метод *zif_capi_callable~call*.
306 |
307 |
308 |
309 | Посмотреть код...
310 |
311 | ```abap
312 | CLASS lcl_task DEFINITION INHERITING FROM zcl_capi_facade_hcm_abstr_task FINAL.
313 | PUBLIC SECTION.
314 |
315 | METHODS:
316 | constructor IMPORTING io_context TYPE REF TO zcl_capi_facade_hcm_abstr_cntx,
317 | zif_capi_callable~call REDEFINITION.
318 |
319 | PRIVATE SECTION.
320 | DATA: ms_params TYPE lcl_context=>ty_params.
321 |
322 | ENDCLASS.
323 |
324 | CLASS lcl_task IMPLEMENTATION.
325 | METHOD constructor.
326 | DATA lo_context TYPE REF TO lcl_context.
327 |
328 | " Set Pernrs numbers to mt_pernrs of Task
329 | super->constructor( io_context ).
330 |
331 | " Set Context parameters
332 | lo_context ?= io_context.
333 | ms_params = lo_context->get_params( ).
334 |
335 | ENDMETHOD.
336 |
337 | METHOD zif_capi_callable~call.
338 |
339 | DATA lt_employees TYPE lcl_result=>ty_t_employees.
340 | DATA ls_employees LIKE LINE OF lt_employees.
341 |
342 | " Simulation of reading the full name of employees by their personnel numbers.
343 | " The ms_params attribute is available here.
344 | " We won't be using it in this example, but you can.
345 |
346 | LOOP AT mt_pernrs ASSIGNING FIELD-SYMBOL().
347 | ls_employees-pernr = -low.
348 |
349 | CASE -low.
350 | WHEN 00000001.
351 | ls_employees-ename = 'John Doe 1'.
352 | WHEN 00000002.
353 | ls_employees-ename = 'John Doe 2'.
354 | WHEN 00000003.
355 | ls_employees-ename = 'John Doe 3'.
356 | WHEN 00000004.
357 | ls_employees-ename = 'John Doe 4'.
358 | WHEN 00000005.
359 | ls_employees-ename = 'John Doe 5'.
360 | WHEN 00000006.
361 | ls_employees-ename = 'John Doe 6'.
362 | WHEN 00000007.
363 | ls_employees-ename = 'John Doe 7'.
364 | WHEN 00000008.
365 | ls_employees-ename = 'John Doe 8'.
366 | WHEN 00000009.
367 | ls_employees-ename = 'John Doe 9'.
368 | WHEN 00000010.
369 | ls_employees-ename = 'John Doe 10'.
370 | WHEN OTHERS.
371 | ENDCASE.
372 |
373 | INSERT ls_employees INTO TABLE lt_employees.
374 | ENDLOOP.
375 |
376 | ro_result = NEW lcl_result( lt_employees ).
377 |
378 | ENDMETHOD.
379 | ENDCLASS.
380 | ```
381 |
382 |
383 |
384 | 3. **lcl_result** описывает *Результат* выполнения задачи.
385 | Этот класс должен реализовывать интерфейс **zif_capi_facade_hcm_result**. В остальном вы можете описать его произвольным образом.
386 |
387 |
388 |
389 | Посмотреть код...
390 |
391 | ```abap
392 | CLASS lcl_result DEFINITION FINAL.
393 | PUBLIC SECTION.
394 | INTERFACES zif_capi_facade_hcm_result.
395 |
396 | TYPES:
397 | BEGIN OF ty_employees,
398 | pernr TYPE n LENGTH 8,
399 | ename TYPE string,
400 | END OF ty_employees,
401 |
402 | ty_t_employees TYPE STANDARD TABLE OF ty_employees WITH KEY pernr.
403 |
404 | METHODS:
405 | constructor IMPORTING it_employees TYPE ty_t_employees.
406 |
407 | PRIVATE SECTION.
408 | DATA: mt_employees TYPE ty_t_employees.
409 |
410 | ENDCLASS.
411 |
412 | CLASS lcl_result IMPLEMENTATION.
413 | METHOD constructor.
414 | mt_employees = it_employees.
415 | ENDMETHOD.
416 |
417 | METHOD zif_capi_facade_hcm_result~get.
418 | et_result = mt_employees.
419 | ENDMETHOD. "get
420 | ENDCLASS.
421 | ```
422 |
423 |
424 | **Внимание:**
425 | Объекты классов **lcl_task** и **lcl_result** сериализуются/десериализуются в процессе выполнения, поэтому избегайте использования статичных атрибутов.
426 |
427 | Итак, объекты *Контекст*, *Задача* и *Результат* описаны.
428 | Теперь рассмотрим пример их применения:
429 |
430 |
431 |
432 | Посмотреть код...
433 |
434 | ```abap
435 | DATA lt_employees TYPE lcl_result=>ty_t_employees.
436 |
437 | " 2 Pernr number per task. For example only.
438 | " '200' will be fine.
439 | DATA(lv_package_size) = 2.
440 |
441 | DATA(ls_params) = VALUE lcl_context=>ty_params( begda = sy-datum
442 | endda = sy-datum ).
443 | DATA(lo_context) = NEW lcl_context( ls_params ).
444 |
445 | DATA(lo_capi_facade_hcm) = NEW zcl_capi_facade_hcm( io_context = lo_context
446 | it_pernrs = gt_pernrs
447 | iv_task_class_name = 'LCL_TASK'
448 | iv_package_size = lv_package_size ).
449 | TRY.
450 | lo_capi_facade_hcm->execute( IMPORTING et_result = lt_employees ).
451 |
452 | WRITE `PERNR ENAME`.
453 | LOOP AT lt_employees ASSIGNING FIELD-SYMBOL().
454 | WRITE: / -pernr, -ename.
455 | ENDLOOP.
456 |
457 | CATCH zcx_capi_tasks_invocation INTO DATA(lo_capi_tasks_invocation).
458 | WRITE lo_capi_tasks_invocation->get_text( ).
459 | ENDTRY.
460 | ```
461 |
462 |
463 | 1. Сначала создаем *Контекст* **lo_context**, который содержит параметры запуска *Задачи*
464 | 2. Далее, создаем *Фасад* **lo_capi_facade_hcm**, конструктор которого имеет 4 параметра:
465 |
466 | | Имя параметра | Описание |
467 | | :-------------------------- | :----------------------------------------------------------- |
468 | | io_context | объект, содержащий параметры запуска задачи |
469 | | it_pernrs | диапазон табельных номеров |
470 | | iv_task_class_name | имя класса Задача |
471 | | iv_package_size | количество табельных номеров на одну задачу |
472 |
473 | 3. У объекта **lo_capi_facade_hcm** вызываем метод *execute( )*, который запускает задачи на параллельное выполнение и возвращает результат.
474 |
475 | Максимальное количество одновременно работающих задач/процессов вычисляется как 40% от числа свободных диалоговых процессов (DIA, sm50).
476 |
477 | Это все, что нужно сделать.
478 |
479 | **Результат работы:**
480 |
481 | 
482 |
483 | Рассмотренный пример использования Фасада для `ABAP Concurrency API` можно найти в отчете **ZCAPI_FACADE_HCM_EXAMPLE**.
484 |
485 |
486 | ## Диаграммы
487 |
488 | UML диаграмма классов ABAP Concurrency API
489 |
490 |
491 |
492 | UML диаграмма классов ABAP Concurrency API для HCM
493 |
498 |
499 |
500 | ## Зависимости
501 | Требуется установленный стандартный пакет разработки **SPTA**.
502 |
503 | ## Ограничения
504 | Пакетный ввод не поддерживается.
505 | Это связано с тем, что API использует стандартный SPTA Framework, в котором перед вызовом CALL FUNCTION STARTING NEW TASK не выполняется проверка того, что максимальное количество сеансов пользовательского интерфейса еще не достигнуто (см. ноты [734205](https://launchpad.support.sap.com/#/notes/734205), [710920](https://launchpad.support.sap.com/#/notes/710920)).
506 |
507 | ## Как внести свой вклад
508 | [Эта инструкция](https://docs.abapgit.org/guide-contributing.html) поможет вам.
509 |
510 | ## Остались вопросы?
511 | Если у вас есть вопросы или предложения не стесняйтесь отправлять их [(GitHub issue)](https://github.com/victorizbitskiy/zconcurrency_api/issues/new).
512 |
513 | ## Логотип
514 | Логотип проекта designed by macrovector/Freepik
515 |
--------------------------------------------------------------------------------