Creating a ABAP in Eclipse plug-in using the ADT SDK – Part 2
In the first part (Creating a ABAP in Eclipse plug-in using the ADT SDK) of this blog series I described the eclipse side of a plug-in enabling the creation of a transport of copies with just one click. In this part I will describe the ABAP side of the plug-in. The full source code of the plug-in as well as a binary release and installation instructions are available on github: ceedee666/adt_transport_utils_plugin · GitHub.
The ADT REST Framework
The ABAP development tools are integrated with the back end system via and RFC and REST (Representational state transfer – Wikipedia, the free encyclopedia) based protocol. A description of the high level architecture of the integration is given in Olga Dolinskajas document Get Started with the ABAP Development Tools for SAP NetWeaver.
In order to enable the registration of new resources in this framework, SAP provides the enhancement spot SADT_REST_RFC_APPLICATION. The enhancement spot defines two BAdIs, BADI_ADT_DISCOVERY_PROVIDER and SADT_REST_RFC_APPLICATION. As the name suggest, the BAdI BADI_ADT_DISCOVERY_PROVIDER is used to implement a discovery provider for a resource. The discovery provider enables the discovery of the concrete URI of a resource in the eclipse plug-in. While it is also possible to hard code the URI of a back end resource in the eclipse plug-in it is recommended to use the discovery service instead. (cf. SAP NetWeaver How-To Guide: SDK for the ABAP Development Tools). Therefore, the eclipse part of the example plug-in implements a getResourceUri() (see the first part of this blog details) for method that uses the discovery provider to get the URI of the back end resource. The BAdI SADT_REST_RFC_APPLICATION is used to implement a custom resource.
The Architecture of the ABAP plug-in
The following images shows an overview of the architecture of the ABAP side of the plug-in. The ABAP side of the plug-in will be called ADT Transport Utils in the remained of this blog.
The RFC handler is the central entry point into the back end for any request from an ABAP development tools plug-in. The RFC handler is part of the ADT REST framework and calls functionality provided by the ADT Transport Utils using the BAdIs mentioned above. ADT Transport Utils consist of two parts. The first part is a custom discovery controller, the ADT Transport Utils Discovery Controller. The custom discovery controller is needed to provide a custom URI schema (i.e. /ztansportutils) to access the resources provided by the ADT Transport Utils. In its current version the ADT Transport Utils provide only one resources, the resource to create transports of copies. This resource consists of the Transport of Copies App and the Transport of Copies controller
Implementing the Discovery Controller
The discovery controller (ZCL_TRANS_UTILS_DISC_RES_CONTR) is implemented by creating a subclass of CL_ADT_RES_APP_BASE and implementing the abstract methods FILL_ROUTER and IF_ADT_REST_RFC_APPLICATION~GET_STATIC_URI_PATH. The following snippet shows the implementation of these two methods. In the GET_STATIC_URI_PATH method the base URI for the ADT Discovery Tools, i.e. /ztansportutils, is returned. The FILL_ROUTER method registers the class CL_ADT_RES_DISCOVERY as the discovery handler for the path template /discovery. As a result any requests to the URI /ztransportutils/discovery will be handled by the class CL_ADT_RES_DISCOVERY.
METHOD fill_router. router->attach( iv_template = '/discovery' iv_handler_class = cl_adt_res_discovery=>co_class_name ). ENDMETHOD. METHOD if_adt_rest_rfc_application~get_static_uri_path. result = zif_trans_utils_constants=>co_trans_utils_static_uri. ENDMETHOD.
After implementing the discovery controller, the next step is to create an implementation of the BAdI BADI_ADT_REST_RFC_APPLICATION and link it to the discovery controller class (ZCL_TRANS_UTILS_DISC_RES_CONTR). Furthermore, the filter value /ztransportutils/discovery needs to be created for the filter STATIC_URI_PATH. This filter value is used by the RFC handler to invoke the correct BAdI for a particular URI. The following screen shot shows the implementation Z_TRANSPORT_UTILS_DISC_RES of the BAdI BADI_ADT_REST_RFC_APPLICATION and the assigned filter value.
Implementing the Transport of Copies Resource
The implementation of the transport of copies resource consist of two parts. The transport of copies resource application (ZCL_TRANS_UTILS_TOC_RES_APP) and the transport of copies resource controller (ZCL_TRANS_UTILS_TOC_RES_CONTR). The resource application is implemented by subclassing CL_ADT_DISC_RES_APP_BASE and implementing its abstract methods. The following code snippet shows the implementation of the resource application class.
CLASS ZCL_TRANS_UTILS_TOC_RES_APP IMPLEMENTATION. METHOD get_application_title. result = zif_trans_utils_constants=>co_trans_utils_app_title. ENDMETHOD. "get_application_title METHOD if_adt_rest_rfc_application~get_static_uri_path. result = zif_trans_utils_constants=>co_create_toc_static_uri. ENDMETHOD. "if_adt_rest_rfc_application~get_static_uri_path METHOD register_resources. registry->register_discoverable_resource( EXPORTING url = zif_trans_utils_constants=>co_create_toc_url handler_class = zif_trans_utils_constants=>co_create_toc_res_controller description = 'Create and optionally release a transport of copies' category_scheme = zif_trans_utils_constants=>co_create_toc_resource_scheme category_term = zif_trans_utils_constants=>co_create_toc_term ). ENDMETHOD. "register_resources ENDCLASS.
The method GET_APPLICATION_TITLE simply return the application title, “Discovery Provider for ADT Transport of Copies” in this case. The IF_ADT_REST_RFC_APPLICATION~GET_STATIC_URI_PATH method returns the URI path (i.e. /ztransportutils/toc_app) for the app. Finally, the REGISTER_RESOURCES method registers the resource controller ZCL_TRANS_UTILS_TOC_RES_CONTR as the handler class for request to the URI /toc/create_toc. As a result. the resource controller will be accessible at the URI /ztransportutils/toc_app/toc/create_toc. In the registration also the category schema and category term are provided. This information is used to discover the concrete URI of the resource in the eclipse plug-in (cf. Creating a ABAP in Eclipse plug-in using the ADT SDK).
After implementing the resource application class, it is used to implement the BADI_ADT_DISCOVERY_PROVIDER and SADT_REST_RFC_APPLICATION BAdIs. Again it is necessary to set appropriate filter values. The implementation Z_TRANPORT_UTILS_TOC_DISC of the BAdI BADI_ADT_DISCOVERY_PROVIDER uses the filter “/ztansportutils/discover = URI”, while the implementation Z_TRANPORT_UTILS_TOC_RES of the BAdI SADT_REST_RFC_APPLICATION uses the filter “STATIC_URI_PATH CP /ztransportutils/toc_app/*”.
The result of these filter values is, that the transport of copies resource is discoverable via the discovery controller and that all request to a URI starting with /ztransportutils/toc_app/ will be forwarded to the resource controller ZCL_TRANS_UTILS_TOC_RES_CONTR.
The final step is the implementation of the resource controller ZCL_TRANS_UTILS_TOC_RES_CONTR. It is implemented by subclassing CL_ADT_REST_RESOURCE. The resource controller has only one public method, the POST method. This method handles all post request send to URI /ztransportutils/toc_app/toc/create_toc. The following snippet show the implementation of the POST method.
In the post method, the transport request to copy and if it should be released are not are read from the query parameters. Using this information the transport of copies is created and optionally released. The source code of the methods used in this snippets are straight forward. Therefore, these methods are not further detailed here. However, the full source code is available at ceedee666/adt_transport_utils_plugin · GitHub
as a SAPLink nugget (http://www.saplink.org).
METHOD post. DATA: trans_request TYPE trkorr, should_be_released TYPE abap_bool, success TYPE abap_bool. trans_request = me->get_transport_request( request ). IF trans_request IS INITIAL. response->set_status( status = cl_rest_status_code=>gc_client_error_bad_request ). RETURN. ENDIF. should_be_released = me->get_should_be_released( request ). TRY. me->create_transport_of_copies( i_trans_request = trans_request i_should_be_released = should_be_released ). response->set_status( status = cl_rest_status_code=>gc_success_ok ). CATCH zcx_trans_utils_exp. response->set_status( status = cl_rest_status_code=>gc_client_error_bad_request ). ENDTRY. ENDMETHOD.
The completion of the ABAP part of the plug-in concludes the second part of the blog series. The final part of the bolg series will describe how to create a deployable plug-in, a corresponding update side and how to make it this update side available using github.