Technical Articles
SAP CPI handles token in Global Variable
In the SAP PI/PO, the process is stateless. When it has a requirement to consume a service by using a token, normally we will fetch the taken each time before consuming the service rather than hold the token till it is expired. Apparently the disadvantage is that the network traffic has been increased.
On the other hand, SAP CPI has lots of ways holding the status.
In this end to end tutorial, we will
- Create an ODATA service that provides a SFLIGHT structure query
The service will use a token as authentication method
The token will be expired every 10 minutes
- Design an iFlow in SAP CPI to consume the service
1 Process Overview
1.1 Detail steps
- POSTMAN sends the request to CPI;
- CPI calls ODATA from ABAP backend and get the response;
- Response has sent back to POSTMAN;
1.2 Technologies involved in the tutorial
- ODATA query development;
- CPI write/read variable;
- CPI Content Modifier;
- CPI Exception handling;
- CPI local call;
- CPI Message Tracing;
1.2.1 Content download
All of the configured iFlow, groovy script, ABAP programs can be downloaded from here
2 Development Steps
2.1 OData Development
If you are not interested in the ABAP OData development, you can skip this part.
Here I used an ABAP ODATA Service working as a Service provider which requires a token. In the real case, it can an ODATA or a generic RESTful service etc.
2.1.1 Create a static class to generate token and token validation check
According to my understanding, a token is periodic expired password. In this case, the first 11 digits of timestamp has been used as a token.
For instance, a full timestamp is: 20200116091124987. It means a time at 09:11:24.987 of 16th of Jan, 2020.
The first 11 digits is 20200116091. It will change every 10 minutes.
However the numeric string looks not similar to a token, we will use a base-64 conversion to make it more beautiful.
This is the method to generate a token
This is the method to valid an input token is valid or not
Since the logic of these two methods are quite straightforward and the full class source code can be get here, i will not go deep into analysing it.
2.1.2 Create Odata Service
2.1.2.1 Create Gateway Service
We are going to create a gateway service with two endpoints:
- Query the SFLIGHT information
- Get a new token
Get into the ABAP backend, TCODE SEGW
Input a name: YGW_SFLIGHT
In this OData Service, we will implement two endpoints:
- Sflight query
- Get a new token
A reusable OData pattern has been used here. I will elaborate it in another Blog Post. The key logic will be analysed here and you can download the whole source code from Github below.
2.1.2.1.1 Sflight Query
This is the source getting ‘token’
lo_facade ?= /iwbep/if_mgw_conv_srv_runtime~get_dp_facade( ).
lt_client_headers = lo_facade->get_request_header( ).
DATA ls_client_headers TYPE ihttpnvp.
READ TABLE lt_client_headers WITH KEY name = 'token'
INTO ls_client_headers.
The ‘token’ is in the variable:
ls_client_headers-value
To check the token is valid or not:
IF ycl_token=>validate( token = ls_client_headers-value ) EQ abap_true.
" Do whatever you want. for this case, it is to ready table SFLIGHT
ENDIF
If the token is not valid use the following code to raise the HTTP exception
CONSTANTS : lc_unauthorized TYPE /iwbep/mgw_http_status_code VALUE '403'.
DATA:
ls_message type SCX_T100KEY.
ls_message-attr1 = 'Token is expired'.
RAISE EXCEPTION TYPE /iwbep/cx_mgw_tech_exception
EXPORTING
http_status_code = lc_unauthorized
textid = ls_message.
This is the code to derive the search condition ‘CARRID’
lt_filters = io_tech_request_context->get_filter( )->get_filter_select_options( ).
IF NOT lt_filters[] IS INITIAL.
* Derive search conditions
READ TABLE lt_filters ASSIGNING <ls_filter> WITH KEY property = 'CARRID'.
IF sy-subrc EQ 0.
LOOP AT <ls_filter>-select_options[] ASSIGNING <ls_select_option>.
APPEND INITIAL LINE TO lt_r_carrid ASSIGNING <ls_r_carrid>.
MOVE-CORRESPONDING <ls_select_option> TO <ls_r_carrid>.
ENDLOOP.
ENDIF.
ENDIF.
This is the source code getting the SFLIGHT records
SELECT *
FROM sflight
INTO TABLE lt_entityset
WHERE carrid IN lt_r_carrid.
IF sy-subrc EQ 0.
/iwbep/if_mgw_conv_srv_runtime~copy_data_to_ref(
EXPORTING
is_data = lt_entityset
CHANGING
cr_data = er_entityset
).
2.1.2.1.2 Get a new token
The logic of this endpoint is very simple. Just two lines of source code:
er_entity-operation = 'GET'.
er_entity-token = ycl_token=>generate( ).
2.1.2.2 Test the service
Get a token
Use the token to make a query
Use the token after few minutes( to test exception raised )
These services will be consumed later by SAP CPI.
2.2 Cloud Connector Configuration
To connect SAP CPI with SAP Backend system, Cloud connector is the recommended application.
SAP CPI configuration can be easily found on google. Here is one for your reference:
http://www.sapspot.com/how-to-guide-connectivity-setup-with-abap-and-sap-cloud-connector/
2.3 CPI iFlow Configuration
The main process of the iFlow will be as below:
- Get the stored token from Global container;
- Use the token to make a query;
- The HTTP error status will trigger an exception occurring;
- The exception catching process will be start;
- The iFlow will call backend getting a new token;
- The iFlow will update the global container by using the new token;
- The iFlow will start again from step 1 and 2.
Here is the detail step
Log into SAP CPI account
2.3.1 Create a Credential
Monitor –> Overview –> Manage Security –> Security Material
Click Add button and choose ‘User Credentials’
After deploying, the credential will be listed here. Record the name and it will be used later.
2.3.2 Create iFlow
Switch to Design view
Select your own folder or create a new folder
Goto tab Artifacts
Click the EDIT button on the top left corner
Select the Add dropdown menu –> Integration Flow
Fill in the information in the popup dialog
there you are. this is the empty iFlow you have created.
2.3.3 Configure the iFlow
Create a sender adapter from Sender to iFlow
Drag and drop Connector to Start event on the right side
Select HTTPS
Input a name for the adapter
Specify an endpoint here and switch off the CSRF check to simply the DEMO
2.3.4 Configure the Main Process
As planned in the first step, we will retrieve a token from global container
Drag and drop a content modifier
In order easy to track trace, give a name Main Process: Set Token in Header
Select the content modifier box and Click Add button
Fill in the values as below
Leave tabs Exchange Property and Message Body blank there
Now we will try to fetch the data from backend
Drag and Drop a Request Reply
Call –> external call –> Request Reply
Input a name: Main Process: Get Sflight
Drag and drop an HTTP adapter from the Request Reply component to system ERPCLNT100
Fill in a name to the adapter
Input {{hostname}}:{{port}} so that these two segments will be parameterized.
Change Proxy type to ‘on promise’ , Method to Get, Authentication to Basic
Credential is configured in the previous chapter
2.3.5 Create Exception Process
Since the token will somehow be expired, we will need a process to catch the exception.
Drag and drop an Exception Subprocess into main process box
Name it as: Main Process: Exception Handling
Here we will create two steps here:
- Get a new token from backend;
- Write the token to the global container;
From call –> local call –> process call, drag and drop two calls into the process flow ‘Main Process: Exception Handling’ as below
Input names for each of them:
- Main Process: Exception Handling: Update a new Token
- Main Process: Exception Handling: Get Sflight
Create a local process for local call Main Process: Exception Handling: Update a new Token
2.3.6 Create a local process Update a new Token
From process à local Integration Process, drag and drop a process into the iFlow
Input a name: Process: Update a new Token
Let it be called by Main Process: Exception Handling: Update a new Token
Select the call Main Process: Exception Handling: Update a new Token of exception handling process
Select tab Processing
Select the process created
Switch back to local process ‘Process: Update a new Token’.
Drag and drop a ‘Request-Reply’ call into the process
Give a name Sub Process: Update a new Token: Get a new Token
Drag and drop an adapter to ERPCLNT100
Fill the name HTTP_Receiver_GetToken to the adapter
Input the values as below:
next step, we will write the token get to the global variable so that it can be derived by any iFlow instance.
Drag and drop a Write Variables process
Name it: Sub Process: Update a new Token: Update Token
this is the entry maintained to the Processing tab page. make sure the Global Scope flag has been checked.
The variable name has to be the same as the one used in the content modifier.
2.3.7 Create a new sub process Get Sflight
The process is the same as the main process
Switch to Exception Handling process, select the process
Drag and drop a Request-Reply to the process
Input url http://{{hostname}}:{{port}}/sap/opu/odata/SAP/YGW_SFLIGHT_SRV/SflightSet
This is the process configured:
2.3.8 IFlow Overview and Deployment
This is the whole iFlow after designing
Deploy the iFlow by clicking the button on the upper right corner.
2.3.9 Configure the iFlow
Input hostname and port for the HTTP adapters used in the iFlow
Deploy the configuration.
Please feel free to Download the iFlow from here
3 Unit Test
Switch the monitor level to trace
Goto monitor, choose the iFlow
Get the endpoint URL
Use POSTMAN to trigger a request call
Check the monitor
you will find that The token is invalid at the first call
This is the New token retrieved
here is the Payload in the last step
Soon after the first call, make a second request from POSTMAN
As we can see, from the message overview, we can see that the first call lasted 3.45 seconds whereas the second one lasted 0.26 seconds
This is the running steps of the second call, which as 7 steps, Compared with the first call which does have 17 steps.
4 Conclusion
By using global variable and write variable steps, the status can be held amount instances of a same CPI iFlow template and it will be better for the performance.