diff --git a/01_Internal_Tables.md b/01_Internal_Tables.md index 3d65b38..ab9e564 100644 --- a/01_Internal_Tables.md +++ b/01_Internal_Tables.md @@ -33,7 +33,7 @@ - [CASTING and ELSE UNASSIGN Additions when Specifying Field Symbols as Target Areas](#casting-and-else-unassign-additions-when-specifying-field-symbols-as-target-areas) - [BINARY SEARCH Addition: Optimized Read Access When Specifying Free Keys](#binary-search-addition-optimized-read-access-when-specifying-free-keys) - [Example: Exploring READ TABLE Statements and Table Expressions](#example-exploring-read-table-statements-and-table-expressions) - - [Table Expressions](#table-expressions) + - [Accessing Single Table Lines via Table Expressions](#accessing-single-table-lines-via-table-expressions) - [Processing Multiple Internal Table Lines Sequentially](#processing-multiple-internal-table-lines-sequentially) - [Restricting the Area of a Table to Be Looped Over](#restricting-the-area-of-a-table-to-be-looped-over) - [Defining the Step Size and the Direction of Loop Passes](#defining-the-step-size-and-the-direction-of-loop-passes) @@ -2903,9 +2903,9 @@ ENDCLASS.
-## Table Expressions +## Accessing Single Table Lines via Table Expressions -Table expressions have been mentioned in sections above. This is to summarize. +The previous sections also covered table expressions. This section provides a summary of their use. - Table expressions typically use the name of an internal table followed by square brackets with content `[ ... ]`, specifying a table line. - They allow read and write access to internal tables at various positions. diff --git a/02_Structures.md b/02_Structures.md index a4f2416..f05ae00 100644 --- a/02_Structures.md +++ b/02_Structures.md @@ -1085,7 +1085,7 @@ are used in the context of local structures. >- By using the optional `AS` addition and specifying a name, the included components can be addressed by this common name as if they were actually components of a substructure. >- The optional `RENAMING WITH SUFFIX` addition, followed by a name, gives the included components a suffix name to avoid naming conflicts with other components. -The following example shows how structured types and data objects are included in another structure. First, three structured types and a structured data object based on one of these types are created. Then, the types and the structure are included in the structured type `address_type`. The executable example demonstrates a structure that includes other structures in this way. +The following example shows how structured types and data objects are included in another structure. First, three structured types and a structured data object based on one of these types are created. Then, the types and the structure are included in the structured type `address_type`. As an excursion, [Runtime Type Identification](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_identific_glosry.htm) is used to retrieve the component names of created structured type `address_type`. Refer to the [Getting Structured Type Information and Creating Structures at Runtime](#getting-structured-type-information-and-creating-structures-at-runtime) section. The executable example demonstrates a structure that includes other structures in this way. ``` abap TYPES: BEGIN OF name_type, title TYPE string, @@ -1108,6 +1108,20 @@ TYPES BEGIN OF address_type. INCLUDE TYPE street_type AS street RENAMING WITH SUFFIX _street. INCLUDE STRUCTURE city_struc AS city RENAMING WITH SUFFIX _city. TYPES END OF address_type. + +DATA component_names type string_table. +LOOP AT CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( 'ADDRESS_TYPE' ) )->components INTO DATA(comp). + APPEND comp-name to component_names. +ENDLOOP. + +*Content of COMPONENT_NAMES: +*TITLE +*PRENAME +*SURNAME +*NAME_STREET +*NUM_STREET +*ZIPCODE_CITY +*NAME_CITY ``` diff --git a/22_Released_ABAP_Classes.md b/22_Released_ABAP_Classes.md index 7f70f85..ca6e4fd 100644 --- a/22_Released_ABAP_Classes.md +++ b/22_Released_ABAP_Classes.md @@ -45,6 +45,7 @@ - [Releasing APIs](#releasing-apis) - [Application Jobs](#application-jobs) - [Generative AI](#generative-ai) + - [Programmatically Creating and Releasing Transport Requests](#programmatically-creating-and-releasing-transport-requests) This ABAP cheat sheet contains a selection of [released](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenreleased_api_glosry.htm) ABAP classes that are available in [ABAP for Cloud Development](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_for_cloud_dev_glosry.htm). It serves as a quick introduction, along with code snippets to explore the functionality in action. @@ -7494,4 +7495,275 @@ ENDTRY. + + +## Programmatically Creating and Releasing Transport Requests + +| Class | Details/Code Snippet | +
XCO_CP_CTS |
+
+
+The following code snippet uses the `XCO_CP_CTS` class, among others, to demonstrate:
+
+- Programmatically creating a transport request
+- Retrieving information about the transport request
+- Excursions:
+ - Programmatically creating a demo class (`ZCL_DEMO_ABAP_CALCULATE`) and assigning it to the new transport request. This simple, executable class inherits from `CL_XCO_CP_ADT_SIMPLE_CLASSRUN` and includes the `calculate` method.
+ - Dynamically calling the `calculate` method to confirm the class creation. For more details, refer to the [Dynamic Programming](06_Dynamic_Programming.md) cheat sheet.
+- Programmatically releasing a transport task and request
+
+> **💡 Note** +> - The example is simplified and non-semantic, exploring various functionalities offered by the XCO APIs. See the repository's [disclaimer](./README.md#%EF%B8%8F-disclaimer). +> - For more information and code snippets, refer to the [SAP Help documentation](https://help.sap.com/docs/btp/sap-business-technology-platform/correction-and-transport-system). +> - The example assumes you have a transportable package, represented by the `pkg_name` constant in the example. +> - To try the example out, create a demo class named `ZCL_DEMO_ABAP` and paste the code into it. Edit the code by providng the `pkg_name` constant with your package name. It is assumed that a demo class named `ZCL_DEMO_ABAP_CALCULATE` does not exist. After activation, choose *F9* in ADT to execute the class. The example is set up to display output in the console. You may also want to open the created `ZCL_DEMO_ABAP_CALCULATE` class. + + + +
+
+🟢 Click to expand for example code+ + ++ +```abap +CLASS zcl_demo_abap DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. + + + +CLASS zcl_demo_abap IMPLEMENTATION. + + METHOD if_oo_adt_classrun~main. + + "Constant names used in the example + "Name of a package that is assigned a demo class that is to be transported + CONSTANTS pkg_name TYPE sxco_package VALUE 'Z_SOME_PACKAGE'. + "Names of a class and a method to be created + CONSTANTS cl_name TYPE sxco_ao_object_name VALUE 'ZCL_DEMO_ABAP_CALCULATE'. + CONSTANTS meth_name TYPE if_xco_gen_clas_s_fo_d_section=>tv_method_name VALUE 'CALCULATE'. + +*&---------------------------------------------------------------------* +*& Creating transport request +*&---------------------------------------------------------------------* + + "Getting transport- and package-related information + DATA(pkg) = xco_cp_abap_repository=>package->for( pkg_name ). + IF pkg->exists( ) = abap_false. + out->write( |Package { pkg_name } does not exist.| ). + RETURN. + ENDIF. + + DATA(pkg_read) = pkg->read( ). + + "Transport layer + DATA(tr_layer) = pkg_read-property-transport_layer->value. + "Transportation target + DATA(tr_target) = pkg_read-property-transport_layer->get_transport_target( )->value. + "Package type + DATA(pkg_type) = pkg_read-property-package_type->value. + "Software component + DATA(software_comp) = pkg_read-property-software_component->name. + + IF tr_layer IS NOT INITIAL. + out->write( |Transport layer: { tr_layer }| ). + ENDIF. + IF tr_target IS NOT INITIAL. + out->write( |Transport target: { tr_target }| ). + ENDIF. + IF pkg_type IS NOT INITIAL. + out->write( |Package type: { pkg_type }| ). + ENDIF. + IF software_comp IS NOT INITIAL. + out->write( |Software component: { software_comp }| ). + ENDIF. + + "Creating transport request with an unclassified task based on the transport target + DATA(tr_request) = xco_cp_cts=>transports->workbench( tr_target )->create_request( 'Some transport request' ). + DATA(tr_req_id) = tr_request->value. + + out->write( |Transport request ID: { tr_req_id }| ). + +* "Attribute information about transport request +* DATA tr_attribute_infos TYPE string_table. +* DATA(tr_attributes) = tr_request->attributes->all->get( ). +* LOOP AT tr_attributes INTO DATA(attr). +* DATA(attr_name) = attr->get_attribute( )->name. +* DATA(attr_value) = attr->get_value( ). +* APPEND |Attribute "{ attr_name }", value "{ attr_value }"| TO tr_attribute_infos. +* ENDLOOP. +* +* IF tr_attribute_infos IS NOT INITIAL. +* out->write( `Transport request attributes:` ). +* out->write( tr_attribute_infos ). +* ENDIF. + + "Transport request status + DATA(tr_status) = tr_request->get_status( )->value. + out->write( |Transport request status: { tr_status }| ). + + "Retrieving information about tasks + DATA(tr_req_tasks) = tr_request->get_tasks( ). + + DATA tr_tasks_info TYPE string_table. + LOOP AT tr_req_tasks INTO DATA(task). + DATA(task_value) = task->value. + DATA(request_of_task) = task->get_request( )->value. + DATA(status_of_task) = task->get_status( )->value. + DATA(task_last_changed) = task->properties( )->get_last_changed( )->as( xco_cp_time=>format->iso_8601_extended )->value. + DATA(task_owner) = task->properties( )->get_owner( )->name. + DATA(task_descr) = task->properties( )->get_short_description( ). + APPEND |Task "{ task_value }", request "{ request_of_task }", status "{ status_of_task }", last changed at "{ task_last_changed }", | && + |owner "{ task_owner }", description "{ task_descr }"| TO tr_tasks_info. + ENDLOOP. + + out->write( `Transport tasks:` ). + out->write( tr_tasks_info ). + +*&---------------------------------------------------------------------* +*& Excursion: Creating a demo class programmatically and assigning it +*& to the transport request +*&---------------------------------------------------------------------* + + DATA(demo_cl) = xco_cp_abap=>class( cl_name ). + + "Checking if the class exists + IF demo_cl->exists( ). + out->write( |Class { cl_name } already exists.| ). + RETURN. + ENDIF. + + "Using the XCO generation API + DATA(env) = xco_cp_generation=>environment->dev_system( tr_req_id ). + DATA(put) = env->create_put_operation( ). + DATA(cl_spec) = put->for-clas->add_object( cl_name )->set_package( pkg_name )->create_form_specification( ). + + "Setting up the class + cl_spec->set_short_description( 'Demo class' ). + cl_spec->definition->set_superclass( 'CL_XCO_CP_ADT_SIMPLE_CLASSRUN' ). + cl_spec->definition->set_create_visibility( xco_cp_abap_objects=>visibility->public ). + cl_spec->definition->set_final( ). + + "Method/type definitions in the public visibility section + cl_spec->definition->section-public->add_method( 'constructor' ). + cl_spec->definition->section-public->add_method( 'main' )->set_redefinition( ). + cl_spec->definition->section-public->add_type( `op` )->for( xco_cp_abap=>type-source->for( 'c LENGTH 1' ) ). + + DATA(calc) = cl_spec->definition->section-public->add_method( meth_name ). + calc->add_importing_parameter( 'num1' )->set_pass_by_reference( )->set_type( xco_cp_abap=>type-source->for( 'i' ) ). + calc->add_importing_parameter( 'operator' )->set_pass_by_reference( )->set_type( xco_cp_abap=>type-source->for( 'op' ) ). + calc->add_importing_parameter( 'num2' )->set_pass_by_reference( )->set_type( xco_cp_abap=>type-source->for( 'i' ) ). + calc->add_returning_parameter( 'result' )->set_type( xco_cp_abap=>type-source->for( 'decfloat34' ) ). + + "Method implementations + cl_spec->implementation->add_method( `constructor` )->set_source( VALUE #( ( `super->constructor( ).` ) ) ). + + cl_spec->implementation->add_method( 'main' )->set_source( VALUE #( ( |DATA(result) = { meth_name }( num1 = 1 operator = '+' num2 = 2 ).| ) + ( `out->write( result ).` ) ) ). + + cl_spec->implementation->add_method( 'calculate' )->set_source( VALUE #( ( `CASE operator.` ) + ( `WHEN '+'. result = num1 + num2.` ) + ( `WHEN '-'. result = num1 - num2.` ) + ( `WHEN '*'. result = num1 * num2.` ) + ( `WHEN '/'. result = num1 / num2.` ) + ( `WHEN OTHERS. result = 0.` ) + ( `ENDCASE.` ) ) ). + + TRY. + DATA(creation_result) = put->execute( ). + out->write( |Class { cl_name } generated.| ). + CATCH cx_xco_gen_put_exception INTO DATA(err). + out->write( err->get_text( ) ). + RETURN. + ENDTRY. + +*&---------------------------------------------------------------------* +*& Excursion: Calling a method in the newly created class dynamically +*&---------------------------------------------------------------------* + + DATA oref TYPE REF TO object. + CREATE OBJECT oref TYPE (cl_name). + + DATA dref TYPE REF TO data. + DATA(type_name) = |{ cl_name }=>OP|. + CREATE DATA dref TYPE (type_name). + dref->* = '*'. + + DATA(ptab) = VALUE abap_parmbind_tab( ( name = 'NUM1' + kind = cl_abap_objectdescr=>exporting + value = NEW i( 5 ) ) + ( name = 'OPERATOR' + kind = cl_abap_objectdescr=>exporting + value = dref ) + ( name = 'NUM2' + kind = cl_abap_objectdescr=>exporting + value = NEW i( 5 ) ) + ( name = 'RESULT' + kind = cl_abap_objectdescr=>returning + value = NEW decfloat34( ) ) ). + + CALL METHOD oref->(meth_name) PARAMETER-TABLE ptab. + + DATA(result) = CONV decfloat34( ptab[ name = 'RESULT' ]-value->* ). + + out->write( |Calculation result when calling method { meth_name } of class { cl_name }: { result }| ). + +*&---------------------------------------------------------------------* +*& Releasing transport tasks and request +*&---------------------------------------------------------------------* + + DATA(cl_handler) = xco_cp_abap_repository=>object->clas->for( cl_name ). + "You might also use the handler demo_cl from above. + + "Checking if the class is locked in a transport request + IF cl_handler->if_xco_cts_changeable~get_object( )->is_locked( ) = abap_true. + DATA(tr_lock) = cl_handler->if_xco_cts_changeable~get_object( + )->get_lock( + )->get_transport( ). + + DATA(tr_req_for_cl) = xco_cp_cts=>transport->for( tr_lock )->get_request( )->value. + out->write( |Class { cl_name } is currently locked in TR { tr_req_for_cl }| ). + ENDIF. + + "Releasing the tasks + DATA(tr_tasks) = tr_request->get_tasks( ). + + LOOP AT tr_tasks INTO DATA(tr_task). + IF tr_task->get_status( ) = xco_cp_transport=>status->modifiable. + tr_task->release( ). + ENDIF. + ENDLOOP. + + "Releasing the transport request + TRY. + tr_request->release( ). + out->write( |Transport { tr_req_id } request released| ). + tr_status = tr_request->get_status( )->value. + out->write( |Transport request status: { tr_status }| ). + CATCH cx_xco_runtime_exception INTO DATA(rel_error). + out->write( rel_error->get_text( ) ). + ENDTRY. + + ENDMETHOD. + +ENDCLASS. +``` + + |
+