├── .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 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/victorizbitskiy/zconcurrency_api/blob/main/LICENSE) 4 | ![ABAP 7.00+](https://img.shields.io/badge/ABAP-7.00%2B-brightgreen) 5 | [![Code Statistics](https://img.shields.io/badge/CodeStatistics-abaplint-blue)](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 | ![result](https://github.com/victorizbitskiy/zconcurrency_api/blob/main/docs/img/result.png) 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 | ![result](https://github.com/victorizbitskiy/zconcurrency_api/blob/main/docs/img/result%20HCM.png) 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 |

UML Class Diagram

493 |
494 |
495 | UML Class Diagram ABAP Concurrency API for HCM module 496 |

UML Class Diagram HCM

497 |
498 |
499 | UML Sequence Diagram 500 |

UML Sequence Diagram

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 | 8 | 9 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /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 | CPUB 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 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/victorizbitskiy/zconcurrency_api/blob/main/LICENSE) 4 | ![ABAP 7.00+](https://img.shields.io/badge/ABAP-7.00%2B-brightgreen) 5 | [![Code Statistics](https://img.shields.io/badge/CodeStatistics-abaplint-blue)](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 | ![result](https://github.com/victorizbitskiy/zconcurrency_api/blob/main/docs/img/result.png) 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 | ![result](https://github.com/victorizbitskiy/zconcurrency_api/blob/main/docs/img/result%20HCM.png) 482 | 483 | Рассмотренный пример использования Фасада для `ABAP Concurrency API` можно найти в отчете **ZCAPI_FACADE_HCM_EXAMPLE**. 484 | 485 | 486 | ## Диаграммы 487 |
488 | UML диаграмма классов ABAP Concurrency API 489 |

UML Class Diagram

490 |
491 |
492 | UML диаграмма классов ABAP Concurrency API для HCM 493 |

UML Class Diagram HCM

494 |
495 |
496 | UML диаграмма последовательности 497 |

UML Sequence Diagram

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 | --------------------------------------------------------------------------------