Mobilize ALV Reports – Part 1 Create RESTful service
Today’s mobility is one of the hot topics in SAP world. Companies are developing new reports and dashboards for mobile environment. Until now lots of custom ALV reports were created and most of their functionality is needed in mobile environment. Rather than new developments for mobile, How can we make this reports mobile enable without modifications?
In this blog series, We will create a Restful service to submit ALV reports and a jquerymobile client to show & visualize report data in mobile.
Before begin, i strongly recommend you to read John Moy ‘s blog .
Part 2 – Create JQueryMobile Web Application with Datatables plugin
Part 3 – Visualize ALV Data with Highcharts for iPad
Creating JSON Restful Service to Submit ALV Reports:
Pre-requisites:
- Go to transaction SE24, copy CL_TREX_JSON_SERIALIZER object to ZCL_TREX_JSON_SERIALIZER and make modifications according to my previous blog post .
Steps:
- Via transaction SE24, create a public class ZCL_SUBMIT_ALV
- Assign interface IF_HTTP_EXTENSION to this class. This should introduce an instance method ‘HANDLE_REQUEST’ to our class.
- For our implementation of HANDLE_REQUEST, paste the following code:
METHOD if_http_extension~handle_request.
TYPE-POOLS: abap,
kkblo.
DATA: lo_json_data TYPE REF TO zcl_trex_json_serializer,
lo_json_metadata TYPE REF TO zcl_trex_json_serializer.
* Data definition
DATA: _path_info TYPE string,
_verb TYPE string,
_callback TYPE string,
_json_string TYPE string,
_json_string_data TYPE string,
_json_string_metadata TYPE string.
DATA: _it_inputparams TYPE tihttpnvp,
_inputparams TYPE LINE OF tihttpnvp.
DATA: _pgmna TYPE tstc–pgmna,
_tcode TYPE tstc–tcode,
_variant TYPE rsvar–variant.
DATA: _data TYPE REF TO data,
_data_line TYPE REF TO data,
_data_descr TYPE REF TO cl_abap_datadescr,
_data_line_descr TYPE REF TO cl_abap_datadescr.
DATA: _datafield(40).
FIELD-SYMBOLS: <_datafield> TYPE ANY.
DATA: BEGIN OF _metadata,
is_hierseq TYPE abap_bool,
tabname TYPE string,
tabname_line TYPE string,
s_keyinfo TYPE kkblo_keyinfo,
s_layout TYPE lvc_s_layo,
t_fcat TYPE lvc_t_fcat,
t_filter TYPE lvc_t_filt,
t_sort TYPE lvc_t_sort,
END OF _metadata.
FIELD-SYMBOLS: <_data> TYPE ANY TABLE,
<_wa_data> TYPE ANY,
<_wa_metadata> TYPE ANY.
DATA: _fcat TYPE lvc_s_fcat.
DATA: _amount(40),
_waersfield(40),
_currfield(40).
DATA: _ttext TYPE tstct–ttext,
_description TYPE char120.
FIELD-SYMBOLS: <_waers> TYPE ANY,
<_currency> TYPE ANY.
* Process request
_path_info = server->request->get_header_field( name = ‘~path_info’ ).
_verb = server->request->get_header_field( name = ‘~request_method’ ).
* Determine if method is get.
IF _verb NE ‘GET’.
CALL METHOD server->response->set_header_field( name = ‘Allow’ value = ‘GET’ ).
CALL METHOD server->response->set_status( code = ‘405’ reason = ‘Method not allowed’ ).
EXIT.
ENDIF.
* Get passed parameters
CALL METHOD server->request->get_form_fields
CHANGING
fields = _it_inputparams.
LOOP AT _it_inputparams INTO _inputparams.
TRANSLATE: _inputparams–name TO UPPER CASE,
_inputparams–value TO UPPER CASE.
MODIFY _it_inputparams FROM _inputparams.
ENDLOOP.
CLEAR _inputparams.
READ TABLE _it_inputparams INTO _inputparams WITH KEY name = ‘TCODE’.
_tcode = _inputparams–value.
CLEAR _inputparams.
READ TABLE _it_inputparams INTO _inputparams WITH KEY name = ‘CALLBACK’.
_callback = _inputparams–value.
CLEAR _inputparams.
READ TABLE _it_inputparams INTO _inputparams WITH KEY name = ‘VARIANT’.
_variant = _inputparams–value.
IF _tcode IS INITIAL.
CALL METHOD server->response->set_status( code = ‘404’ reason = ‘Parameter missing’ ).
CALL METHOD server->response->set_cdata( data = ‘Input Paramater “tcode” is missing’ ).
EXIT.
ENDIF.
* progname of tcode
SELECT SINGLE pgmna
INTO _pgmna
FROM tstc
WHERE tcode = _tcode.
IF sy-subrc IS NOT INITIAL.
CALL METHOD server->response->set_status( code = ‘404’ reason = ‘Tcode not exist’ ).
CALL METHOD server->response->set_cdata( data = ‘Input Paramater “tcode” is not exist’ ).
EXIT.
ENDIF.
cl_salv_bs_runtime_info=>set( EXPORTING display = abap_false
metadata = abap_true
data = abap_true ).
IF _variant IS INITIAL.
SUBMIT (_pgmna) AND RETURN.
ELSE.
DATA: _it_valutab TYPE STANDARD TABLE OF rsparams.
CALL FUNCTION ‘RS_VARIANT_CONTENTS’
EXPORTING
report = _pgmna
variant = _variant
TABLES
valutab = _it_valutab
EXCEPTIONS
variant_non_existent = 1
variant_obsolete = 2
OTHERS = 3.
IF _it_valutab[] IS INITIAL.
SUBMIT (_pgmna) AND RETURN.
ELSE.
* SUBMIT (_pgmna) WITH SELECTION-TABLE _it_valutab AND RETURN.
SUBMIT (_pgmna) USING SELECTION–SET _variant AND RETURN.
ENDIF.
ENDIF.
TRY.
cl_salv_bs_runtime_info=>get_data_ref( IMPORTING
r_data = _data
“r_data_line = _data_line
r_data_descr = _data_descr
r_data_line_descr = _data_line_descr ).
cl_salv_bs_runtime_info=>get_metadata( RECEIVING value = _metadata ).
ASSIGN _data->* TO <_data>.
* Modify data for output
LOOP AT <_data> ASSIGNING <_wa_data>.
* Modify data with conversion routines
LOOP AT _metadata–t_fcat INTO _fcat WHERE edit_mask IS NOT INITIAL
AND inttype = ‘C’.
CONCATENATE ‘<_WA_DATA>-‘
_fcat–fieldname
INTO _datafield.
ASSIGN (_datafield) TO <_datafield>.
WRITE <_datafield> TO <_datafield> USING EDIT MASK _fcat–edit_mask.
ENDLOOP.
* Modify currency amount
LOOP AT _metadata–t_fcat INTO _fcat WHERE datatype = ‘CURR’
AND cfieldname IS NOT INITIAL.
CONCATENATE ‘<_WA_DATA>-‘
_fcat–cfieldname
INTO _waersfield.
CONCATENATE ‘<_WA_DATA>-‘
_fcat–fieldname
INTO _currfield.
ASSIGN: (_waersfield) TO <_waers>,
(_currfield) TO <_currency>.
CALL FUNCTION ‘CURRENCY_AMOUNT_SAP_TO_IDOC’
EXPORTING
currency = <_waers>
sap_amount = <_currency>
IMPORTING
idoc_amount = _amount.
CONDENSE _amount.
<_currency> = _amount.
ENDLOOP.
ENDLOOP.
CATCH cx_salv_bs_sc_runtime_info.
* If error detected then abort
CALL METHOD server->response->set_status( code = ‘404’ reason = ‘Unable to retrieve ALV data’ ).
CALL METHOD server->response->set_cdata( data = _json_string ).
EXIT.
ENDTRY.
cl_salv_bs_runtime_info=>clear_all( ).
* create instance of json serialiser
CREATE OBJECT lo_json_data
EXPORTING
DATA = <_data>.
* serialize data
lo_json_data->serialize( ).
* get serialized json data string
_json_string_data = lo_json_data->get_data( ).
* create instance of json serialiser
CREATE OBJECT lo_json_metadata
EXPORTING
DATA = _metadata–t_fcat.
* serialize metadata
lo_json_metadata->serialize( ).
* get serialized json metadata string
_json_string_metadata = lo_json_metadata->get_data( ).
IF _json_string_metadata IS NOT INITIAL.
CONCATENATE ‘”alvMetadata”:’ _json_string_metadata INTO _json_string_metadata SEPARATED BY space.
ENDIF.
IF _json_string_data IS NOT INITIAL.
CONCATENATE ‘”alvData”:’ _json_string_data INTO _json_string_data SEPARATED BY space.
ENDIF.
* Tcode description
SELECT SINGLE ttext
INTO _ttext
FROM tstct
WHERE sprsl = sy–langu
AND tcode = _tcode.
CONCATENATE ‘”description”:”‘
_ttext
‘”‘
INTO _description.
* JSON
CONCATENATE ‘{‘
_description
‘,’
_json_string_metadata
‘,’
_json_string_data
‘}’
INTO _json_string
SEPARATED BY space.
* to support JSONP
CONCATENATE _callback
‘(‘
_json_string
‘)’
INTO _json_string.
*
* set the response mimetype to json
* Set the content type
CALL METHOD server->response->set_header_field(
name = ‘Content-Type’
value = ‘application/json; charset=utf-8’ “for JSON
).
* Set CORS access control to avoid browser policy restrictions around
* Cross Domain communication
CALL METHOD server->response->set_header_field( name = ‘Access-Control-Allow-Origin’ value = ‘*’ ).
** set Allow methods
* CALL METHOD server->response->set_header_field( name = ‘Access-Control-Allow-Methods’ value = ‘GET’ ).
* set the cdata response to the json string
CALL METHOD server->response->set_cdata( data = _json_string ).
ENDMETHOD. “if_http_extension~handle_request
Publish Service:
Steps:
- Via transaction SICF, create a new service ‘zsubmitalv’ under the path /default_host/sap/bc/
- For the service, add a description, then go to the ‘Handler List’ tab and add “ZCL_SUBMIT_ALV” into the handler list.
- Activate the service (from the SICF tree, right-click on the service and select ‘Activate Service’)
Test Service:
Steps:
- From the SICF tree, right-click on the service and select ‘Test Service’ , you will see service respond: ‘Input Paramater “tcode” is missing‘
- Take url from browser and pass your transaction code as parameter like http://yoursapurl:8000/sap/bc/zsubmitalv?tcode=ZALVREPORT .Via this url you will get alv metadata and data in JSON format.
You can also pass variant as parameter:
Ex: http://yoursapurl:8000/sap/bc/zsubmitalv?tcode=ZALVREPORT&variant=MYVARIANT
Note:
In ALV, maybe there is “CNTL_ERROR” dump because of the background execution.
To avoid this problem;
1- For reports that was created with REUSE_ALV_GRID_DISPLAY, You have to pass IT_SORT paramater to function.(it can be initial)
DATA: _it_field_catalog TYPE slis_t_fieldcat_alv,
_it_sort_catalog TYPE slis_t_sortinfo_alv ,
_layout TYPE slis_layout_alv,
_title TYPE lvc_title,
_repid LIKE sy–repid.
_repid = sy–repid.
_layout–colwidth_optimize = ‘X’.
_layout–zebra = ‘X’.
CALL FUNCTION ‘REUSE_ALV_GRID_DISPLAY’
EXPORTING
i_callback_program = _repid
i_grid_title = _title
i_save = ‘A’
is_layout = _layout
it_fieldcat = _it_field_catalog
it_sort = _it_sort_catalog
TABLES
t_outtab = p_it_output[]
EXCEPTIONS
program_error = 1
OTHERS = 2.
2- In OO ALV add offline mode control before creation of custom container in pbo of alv screen
IF cl_gui_alv_grid=>offline( ) IS INITIAL. “Offline mode control
CREATE OBJECT g_custom_container
EXPORTING
container_name = g_container.
ENDIF.
CREATE OBJECT g_grid
EXPORTING
i_parent = g_custom_container.
Really smart topic and interesting post.
Bravo!
Thank You!!
Great use of cl_salv_bs_runtime_info to get the table data, it's a really interesting approach. You're right, the techniques you've employed here could work really well with zMob. The architecture you've used is not dissimilar to that of zMob's either, so it may not be so complicated to integrate 🙂
Thanks for the heads up,
Hi Basar Ozgur Kahraman,
Nice document ..,
When I'm trying to implement the same its giving dump as
500 SAP Internal Server Error
ERROR: Program not found. (termination: RABAX_STATE)
The URL is :
http://eccdcs1s.mydrreddys.com:8001/sap/bc/zsubmitalv?sap-client=000&tcode=XXXXXX&variant=MYVARIANT
Regards,
Lokesh.
Hi Lokeswar,
i think it got this dump while submitting program. Please, check this sql statement result and be sure transaction code exist in your system.
SELECT SINGLE pgmna
INTO _pgmna
FROM tstc
WHERE tcode = _tcode.
Regards,
Basar Ozgur
Hi Basar,
Its working now its the issue with Tcode ,
Thanks a lot ..,
Lokeswar.
Hi,
Really Nice post.
I tried this one, it is working on PC.
Is this working in ANDROID EMULATOR or Device?
Hi Satya,
i tried on Android 2.3 and 4.1, working smoothly on devices. i haven't tried it on Android Emulator.
Hi,
Actually i tried in another system, in that system SAP is not installed.
some Error occurred .
Is it necessary to install SAP.
Hi,
Sure, and also you need to have ITS restful service for each sap system to connect and call reports.
Hi,
How Can i try in mobile device.
Hi,
In device, open browser and go to page MySapReport, fill connection settings then you can try.
Regards
Hi,
I tried in Android Device But the same error occured.
Hi Satya,
Are you sure about service is running and settings is OK? Follow me on scn so you can reach me with direct messages. i will help you in private and share results here..
Regards
For community: we discussed with Satya via direct messages. The reason of issue is connection problem between device and ITS.
That was amazing Başar,keep sharing like these...
Hi Basar,
I'm new in the SAP world and thanks for your article, it was really helpful and solve some issues with this kind of implementation.
In the Test, Step 1, I got the tcode is missing, ok I put it on the url but now the message is:
"Input Parameter "tcode" is not exists "
I know that I will need a transaction code: "zalvreport" but I don't know how it's the best way or option to create it, I see some blogs on internet that explain process in the tcode se93 but I don't feel able to create all stuff.
Could you explain me please how it's the best way to create the transaction and how can I run the:
SELECT SINGLE pgmna
INTO _pgmna
FROM tstc
WHERE tcode = _tcode.
Thanks before hand.
F.G.
Hi Felipe,
This tool is using your EXISTING tcodes that creates ALV outputs so you don't need to create a tcode. You pass any tcode that EXIST in your system. There isn't any 'zalvreport' tcode in your system so you get this error.
Regards
Basar Ozgur
Hi Basar, thanks for your answer.
So, I see that I need to create an ALV report that has a specific output.
In your example, this means tcoce: ZSD35 with the variant: "DEFAULT" as shows in the next img:
http://scn.sap.com/servlet/JiveServlet/showImage/38-72286-139867/js.jpg
Do you have any example or tutorial for create this ALV report ZSD35 for apply correctly to this implementation?
Thanks !
F.G.
Hi Felipe,
You can use this program to test. After creation, Don't forget to create a tcode for this program. Because you have to pass tcode to service parameter
Hi Basar,
I check your link and I implemented as a program into my SAP system on the SE80 with the name zprogramtest,
Then I created a transaction code "zalvreport" in the: SE93, with short text, and with "Program and selection screen (Report Transaction)",
After that, I linked the zprogramtest on the new transaction zalvreport in the "program" input and save
Restart my service and... It works! thank you so much, thumbs up!
So the last conclusion it's we need to implement ALV report according with the need, so the create a tcode and launch in the webservice.
Thanks again!
F.G.
Hi Felipe,
Glad to hear that. good luck! 🙂