Quantcast
Channel: SCN : Blog List - ABAP Connectivity
Viewing all 68 articles
Browse latest View live

Google Knowledge Graph Search API, schema.org and JSON-LD

$
0
0

A couple of weeks ago I've heard about the Google Knowledge Graph API for the first time. All of you who followed my work in the last years probably know that I'm interested in all kind of public APIs and Graph Databases. Obviously I've started to play around with this API immediatelly.


As described on https://developers.google.com/knowledge-graph/ I've registered my user and got an API key.


My first call: https://kgsearch.googleapis.com/v1/entities:search?query=chuck%20norris&key=my_API_key&limit=1

{
  "@context": {
    "@vocab": "http://schema.org/",
    "goog": "http://schema.googleapis.com/",
    "EntitySearchResult": "goog:EntitySearchResult",
    "detailedDescription": "goog:detailedDescription",
    "resultScore": "goog:resultScore",
    "kg": "http://g.co/kg"
  },
  "@type": "ItemList",
  "itemListElement": [
    {
      "@type": "EntitySearchResult",
      "result": {
        "@id": "kg:/m/015lhm",
        "name": "Chuck Norris",
        "@type": [
          "Person",
          "Thing"
        ],
        "description": "Martial Artist",
        "image": {
          "contentUrl": "http://t3.gstatic.com/images?q=tbn:ANd9GcTOLvRnq7ANkycMmFAT0UoC1kzQXFAzBUkBTOEMMJvLMMXu-QWt",
          "url": "https://en.wikipedia.org/wiki/Chuck_Norris"
        },
        "detailedDescription": {
          "articleBody": "Carlos Ray \"Chuck\" Norris is an American martial artist, actor, film producer and screenwriter. After serving in the United States Air Force, he began his rise to fame as a martial artist, and has since founded his own school, Chun Kuk Do.\n",
          "url": "http://en.wikipedia.org/wiki/Chuck_Norris",
          "license": "https://en.wikipedia.org/wiki/Wikipedia:Text_of_Creative_Commons_Attribution-ShareAlike_3.0_Unported_License"
        },
        "url": "http://www.chucknorris.com/"
      },
      "resultScore": 729.463074
    }
  ]
}

Not really "Knowledge Graph" style. Where is the linked data like movies etc.?


Back to the homepage. Et voilà, better read before you judge:

"Note: The Knowledge Graph Search API returns only individual matching entities, rather than graphs of interconnected entities. If you need the latter, we recommend using data dumps from Wikidata instead."

 

But why Google calls it "Knowledge Graph Search" then? Hopefully they'll change their minds in the near future...

Nevertheless, I've created a new ABAP Open Source project to use the Google Knowledge Graph Search: zGKGS


Google Knowledge Graph Search API for ABAP

 

With just a few lines of code you get nice results:

 

DATA(google_knowledge_graph_search) =NEW zcl_gkgs_api( i_api_key ='Your_API_Key' ).

google_knowledge_graph_search->search(
  EXPORTING
    i_query     ='sap'
    i_limit     =5
  IMPORTING
    e_results   = DATA(results)
).

LOOPAT results ASSIGNINGFIELD-SYMBOL(<result>).

  cl_demo_output=>begin_section( title =<result>->get_result( )->get_description( ) ).

  IF<result>->get_result( )->get_image( ) ISBOUND.
    cl_demo_output=>write_html( html =|<image src="{<result>->get_result( )->get_image( )->get_content_url( ) }"/>| ).
  ENDIF.

  cl_demo_output=>write_text( <result>->get_result( )->get_detailed_description( )->get_article_body( ) ).
  cl_demo_output=>end_section( ).

ENDLOOP.

cl_demo_output=>display( ).

search.png

How does it work? Well, the most interesting part of zGKGS is my next open source project: SchemA


SchemA: The schema.org ABAP framework


What is schema.org?

"Schema.org is a collaborative, community activity with a mission to create, maintain, and promote schemas for structured data on the Internet, on web pages, in email messages, and beyond."


It's a project sponsored by Google, Microsoft, Yahoo and Yandex and runs under the hood of W3C. More information you can find on the homepage of schema.org.


Based on the schema.org objects, I've created an OO framework in ABAP. Let's look at an example:

 

DATA(organization) =NEW zcl_schema_organization( ).

organization->set_legal_name( 'SAP SE' ).
organization->set_founding_date( '19720401' ).
organization->set_address( NEW#( ) ).
organization->get_address( )->set_address_country( 'DE' ).
organization->get_address( )->set_address_locality( 'Walldorf' ).

DATA(founder) = organization->get_founder( ).
INSERTNEW zcl_schema_person( ) INTOTABLE founder ASSIGNINGFIELD-SYMBOL(<founder>).
<founder>->set_name( 'Claus Wellenreuther' ).
INSERTNEW zcl_schema_person( ) INTOTABLE founder ASSIGNING<founder>.
<founder>->set_name( 'Hans-Werner Hector' ).
INSERTNEW zcl_schema_person( ) INTOTABLE founder ASSIGNING<founder>.
<founder>->set_name( 'Klaus Tschira' ).
INSERTNEW zcl_schema_person( ) INTOTABLE founder ASSIGNING<founder>.
<founder>->set_name( 'Dietmar Hopp' ).
INSERTNEW zcl_schema_person( ) INTOTABLE founder ASSIGNING<founder>.
<founder>->set_name( 'Hasso Plattner' ).
organization->set_founder( founder ).

cl_demo_output=>display_json( organization->get_json( ) ).

 

If (hopefully) everything works fine you'll get a response in JSON-LD (linked data) format:

 

 

{
"@context":
{
  "@vocab":"http://schema.org/"
},
"@type":"Organization",
"address":
{
  "@type":"PostalAddress",
  "addressCountry":"DE",
  "addressLocality":"Walldorf"
},
"founder":
[
  {
   "@type":"Person",
   "name":"Claus Wellenreuther"
  },
  {
   "@type":"Person",
   "name":"Hans-Werner Hector"
  },
  {
   "@type":"Person",
   "name":"Klaus Tschira"
  },
  {
   "@type":"Person",
   "name":"Dietmar Hopp"
  },
  {
   "@type":"Person",
   "name":"Hasso Plattner"
  }
],
"foundingDate":"1972-04-01",
"legalName":"SAP SE"
}

To validate the output, you can copy the string and paste it into the JSON-LD playground page on http://json-ld.org/playground/ .


Need help


If you look at the page http://schema.org/docs/full.html you'll see, that there are hundreds of objects to be created in ABAP. If you want to support the SchemA project, please go to the project wiki under https://github.com/se38/SchemA/wiki/How-to-contribute-to-the-project and read the instructions (will be created soon). Thank you!


These projects are created under NW7.50 SP1 and tested under NW740 SP10 but the target version should be NW7.40 SP8, so please let me know if there are some syntax errors.


Conclusion

 

The next time your supplier of choice asks you in which format they can expect your purchase order, just response with: http://schema.org/Order


How To Use Python via External OS Commands and Embed the Scripts Seamlessly

$
0
0

Hello community,

 

it is not very exciting to bind an external command via TAC SM69 on an SAP system. It is also not very exciting to use the external command via the function module SXPG_COMMAND_EXECUTE. But it is interesting to combine different possibilities in this context.

 

The external OS command is a scripting language, in my case Python. After the configuration of the TAC SM69 we set with the TAC FILE a logical and physical path to the target directory where the Python files should be stored on the application server. And now we can use this customizing in a function module, which reads the Python script from an ABAP include, stores, executes and delete it.

 

  1. Customizing in TAC SM69
    005.jpg
  2. Customizing in TAC FILE (logical and physical path)
    003.jpg
    004.jpg
  3. Now we store the Python script as include.
    006.jpg

    # -*- coding: iso-8859-15 -*-
    #-Begin-----------------------------------------------------------------
    
    #-Imports---------------------------------------------------------------
    import platform, struct
    
    #-Sub Main--------------------------------------------------------------
    def main():
      print("Hello World from Python", platform.python_version(), "on",     platform.system(), "(" + platform.architecture()[0] + ")")
    
    #-Main------------------------------------------------------------------
    if __name__ == "__main__":
      main()
    
    #-End-------------------------------------------------------------------
    
  4. Now we can use the Python script from the include and the Python interpreter from the external command to executes the script and to use the result in our ABAP environment,

    Function ZEXECUTEPYTHONSCRIPT.
    *"----------------------------------------------------------------------
    *"*"Lokale Schnittstelle:
    *"  IMPORTING
    *"     VALUE(I_INCLNAME) TYPE  SOBJ_NAME
    *"     VALUE(I_FILENAME) TYPE  STRING
    *"  EXPORTING
    *"     VALUE(E_EXECPROT) TYPE  Z_TAB_BTCXPGLOG
    *"  EXCEPTIONS
    *"      NO_FILE_NAME
    *"      NO_INCLUDE_AVAILABLE
    *"      CAN_NOT_WRITE_SCRIPT
    *"      ERROR_IN_SCRIPT_EXECUTION
    *"      CAN_NOT_DELETE_SCRIPT
    *"----------------------------------------------------------------------  "-Variables-----------------------------------------------------------    Data lv_FileName(255) Type c.    Data lv_TADIR Type TADIR.    Data lt_Incl Type Table Of String.    Data lv_lineIncl Type String.    Data lv_strIncl Type String.    Data lv_Status Type EXTCMDEXEX-STATUS.    Data lv_ExitCode Type EXTCMDEXEX-EXITCODE.  "-Main----------------------------------------------------------------    "-Gets directory path-----------------------------------------------      Call Function 'FILE_GET_NAME'        Exporting          CLIENT = sy-mandt          LOGICAL_FILENAME = 'ZPYTHON'          OPERATING_SYSTEM = sy-opsys          PARAMETER_1  = i_FileName          ELEMINATE_BLANKS = 'X'        Importing          FILE_NAME = lv_FileName        Exceptions          FILE_NOT_FOUND   = 1          Others           = 2.      If sy-subrc <> 0.        Raise NO_FILE_NAME.      EndIf.    "-Gets script content-----------------------------------------------      Select Single * From TADIR Into lv_TADIR        Where OBJ_NAME = i_InclName.      If sy-subrc = 0.        Read Report i_InclName Into lt_Incl.        If sy-subrc = 0.          Loop At lt_Incl Into lv_lineIncl.            lv_strIncl = lv_strIncl && lv_lineIncl &&              cl_abap_char_utilities=>cr_lf.          EndLoop.        EndIf.      Else.        Raise NO_INCLUDE_AVAILABLE.      EndIf.    "-Writes script-----------------------------------------------------      Open Dataset lv_FileName For Output In Text Mode        Encoding Non-Unicode With Windows Linefeed.      If sy-subrc = 0.        Transfer lv_strIncl To lv_FileName.        Close Dataset lv_FileName.      Else.        Raise CAN_NOT_WRITE_SCRIPT.      EndIf.    "-Executes script---------------------------------------------------      Call Function 'SXPG_STEP_COMMAND_START'        Exporting          COMMANDNAME = 'ZPYTHON'          ADDITIONAL_PARAMETERS = lv_FileName          OPERATINGSYSTEM = sy-opsys          STDINCNTL = 'R'          STDOUTCNTL = 'M'          STDERRCNTL = 'M'          TRACECNTL = '0'          TERMCNTL = 'C'        Tables          LOG = e_ExecProt        Exceptions          COMMAND_NOT_FOUND = 1          PARAMETER_EXPECTED = 2          PARAMETERS_TOO_LONG = 3          SECURITY_RISK = 4          WRONG_CHECK_CALL_INTERFACE = 5          NO_PERMISSION = 6          UNKNOWN_ERROR = 7          COMMUNICATION_ERROR = 8          SYSTEM_ERROR = 9          CANNOT_GET_RFC_DESTS = 10          JOB_UPDATE_FAILED = 11          JOB_DOES_NOT_EXIST = 12          PROGRAM_START_ERROR = 13          Others = 14.        If sy-subrc <> 0.          Raise ERROR_IN_SCRIPT_EXECUTION.        EndIf.    "-Deletes script----------------------------------------------------      Delete Dataset lv_FileName.      If sy-subrc <> 0.        Raise CAN_NOT_DELETE_SCRIPT.      EndIf.
    
    EndFunction.
    

    001.jpg
    002.jpg
    Hint: In this case I use the same method as the program SAPLSXPT. In a normal case you should use the function module SXPG_COMMAND_EXECUTE.

The tiny idea behind this method is that is not necessary to store the script files permanently on the file system of your application server. You can save it as includes in your ABAP environment and transfer it on demand, if you need it.

 

Enjoy it.

 

Cheers

Stefan

Connect ABAP with R via FastRWeb running on Rserve

$
0
0

 

Intro

A time ago we evaluted the Integration of R in SAP HANA (SAP HANA R Integration Guide - SAP Library) to be able to execute statistical calculations using the wide range of available open source R implementations of statistical algorithms. During the evaluation we also thought about the option to directly integrate R in ABAP without SAP HANA, for such customers who do not plan to migrate to SAP HANA in the near future or do not want to call a RLANG procedure on SAP HANA from ABAP. The result was a little tool called FastRWebABAPConnector which integrates R in ABAP using Rserve and the additional component FastRWeb. Rserve is a TCP/IP server which allows the execution of R script code. FastRWeb uses the integrated webserver of Rserve >1.7 (or any other webserver) to allow access to the R script coding stored on the server via HTTP(s). Via a simple URL a R script can be executed. The only pre-condition is that the R script file contains a function "run" which is called by the FastRWeb component. The "run" function can have n input parameters which are mapped to the URL parameters used for the URL call. If for instance the run function has an input parameter named "inputData", the URL has to be called with "?inputData=Test" to transfer the value "Test" to the input parameter.

 

On the SAP NetWeaver ABAP side the connection to the Rserve/FastRWeb HTTP server is done by a "HTTP connection to external server" RFC connection maintained in transaction SM59. The connection points to the host/port under which the HTTP server component of Rserve is avaialable. Making requests to the HTTP server is done by the ABAP HTTP client class CL_HTTP_CLIENT.

 

The solution allows executing R script coding which does calculations or creates plots. Structured input/result parameters are transferred in JSON format. JSON serizalizing/deserializing is done on ABAP side using the standard ABAP transformation functionality which is available since NW 7.40 (in older releases one of the open source ABAP implementations could be used). On R side the serialization/deserialization functionality of R library jsonlite is used. Returning plots from R to ABAP is done by returning just the binary string of the created plot.


Following component model shows the high level architecture.

01_architecture.png

 

Configuration

In the following steps I describe briefly what configuration steps are necessary regarding Rserve/FastRWeb and I explain the details of the FastRWebABAPConnector component. I will not go into the very deep details of each step regarding the configuration, because the open source product sites already provide good installation guides and tips. One thing to mention is, that for the evaluation I used Rserve for Windows, for production scenarios always Rserve on a Linux bases systemhas to be used, because the Windows version has some limitations (for instance regarding concurrent processing).

 

Rserve

Pre-condition to install Rserve is of course to have installed an R Runtime. Rserve itself can be installed either by downloading and extracting the binary for the relevant platform from Rserve - Binary R server - download/files - RForge.net or via the R console (I use the console of RStudio) with command install.packages("Rserve"). To start the Rserve TCP/IP server in the R console the Rserve library has to be loaded with library("Rserve"). After that the process can be executed by calling function Rserve(). The Rserve TCP/IP server can be reached by default on port 6311. For an easier start up process it is recommended to create a shell script which starts the Rserve TCP/IP server using the executable for Rserve which can be found in the Rserve installation folder.

FastRWeb

After the Rserve TCP/IP server is installed the FastRWeb component can be installed and configured. In the following steps the %R_HOME% is the placeholder for the R runtime installation folder. All paths are related to a Windows x64 systems.

 

StepDescription
Install FastRWeb packageInstall the FastRWeb package using the R console with command install.packages("FastRWeb"). As result the FastRWeb sources are available in folder %R_HOME%\library\FastRWeb.
Copy Rserve files to R binary folderThe files "Rserve.dll", "Rserve.exe" and "Reserve_d.exe" have to be copied from folder %R_HOME%\library\Rserve\libs\x64 to folder %R_HOME%\bin\x64. Copying the files is necessary because the "R.dll" file stored in the target folder is necessary for the execution of the executables. Remark: With additional configuration it is not necessary to copy the files.
FastRWeb Rserve configuration

For a proper execution of FastRWeb on Rserve following configuration settings have to be done in file "rserve.conf" located in folder %R_HOME%\library\FastRWeb\code.

 

http.port 9060

http.raw.body TRUE

root C:/Program Files/R/R-3.2.2/library/FastRWeb

source C:/Program Files/R/R-3.2.2/library/FastRWeb/code/rserve.R

FastRWeb.root C:/Program Files/R/R-3.2.2/library/FastRWeb

control assent

 

The HTTP port of the FastRWeb Component, the FastRWeb roots and the R script which is executed during the server start are maintained. In that example the web server is reachable at port 9060.

Rserve R start script

During the start up of Rserve a R script is executed. As defined in the step before for the FastRWeb configuration it is the script "rserve.R" located in folder %R_HOME%\library\FastRWeb\code. The script has to be enhanced at the beginning with following lines to load the FastRWeb package and to handle HTTP requests via FastRWeb.

 

library("FastRWeb")

.http.request <- FastRWeb:::.http.request

Store R Scripts in web folder

R scripts to be called by a URL have to be stored in folder %R_HOME%\library\FastRWeb\web.R. That is the web folder of the FastRWeb component.

 

For instance a script named "test.R" is then available via URL http(s)://<host>:<port>/test.

Script to start Rserve with FastRWeb configuration

It is recommended to create a shell script to start the Rserve TCP/IP server with the specific FastRWeb configuration within folder %R_HOME%\bin\x64.

 

For instance:

R CMD Rserve_d.exe --RS-conf "C:\Program Files\R\R3.2.2\library\FastRWeb\code\rserve.conf"

FastRWeb ABAP Connector

To connect ABAP to FastRWeb respectively to a specific R script hosted on the web server, class CL_HTTP_CLIENT is used. To avoid hard coded host and port information for the web server in the ABAP coding, the connection settings are stored in a "HTTP Connection to External Server" RFC connection which is maintained in transaction SM59. Using method CREATE_BY_DESTINATION of class CL_HTTP_CLIENT, a HTTP client for that destination can be created. The following image shows the configuration of the destination using the host and the port configured for the web server.

 

02_rfc_destination.png

Parameters are transferred to the R scripts from ABAP as JSON strings in URL parameters. To convert internal values like structures and tables, the ABAP integrated ABAP JSON transformation functionality is used. Also the result is returned as JSON string, except in case a plot R script is called. Plot R scripts return the result as binary string.

 

For a comfortable way of calling R scripts without doing the HTTP call and the JSON transformation manually, an FastRWebABAPConnector adapter was implemented which encapsulates these things. The sources are available at GitHub. The adapter consists of interface ZZ_IF_FASTRWEB_CONNECTOR and class ZZ_CL_FASTRWEB_CONNECTOR.

 

The usage of the adapter can be seen in following dummy example.

" create FastRWeb Connector instance

DATA(lo_rcon) =

  NEW zz_cl_fastrweb_connector(

    iv_result_type = zz_if_fastrweb_connector=>mc_result_type_json

    iv_destination = 'Z_RSERVE_FP'  " RFC Destination pointing to web server

    iv_rscript_path = '/R/test' ).  " path to R script in web folder + name of R script w/o file extension

 

" set input parameter

DATA lt_parameter TYPE zz_if_fastrweb_connector=>mtt_key_value.

DATA(lt_test) = value ltt_test( ... ).

APPEND VALUE #( key = 'inputTable' value = REF #( lt_test ) ) TO lt_parameter.

 

DATA(ls_settings) = VALUE lts_test( ... ).

APPEND VALUE #( key = 'inputTest' value = REF #( ls_test ) ) TO lt_parameter.

 

" set result variable

DATA lt_result TYPE zz_if_fastrweb_connector=>mtt_key_value.

DATA lt_cluster TYPE ltt_result.

APPEND VALUE #( key = zz_if_fastrweb_connector=>mc_result_key

                value = REF #( lt_calc_result ) ) TO lt_result.

 

" execute R script

TRY.

  lo_rcon->execute_script( EXPORTING it_parameter = lt_parameter

                           CHANGING ct_result = lt_result ).

CATCH cx_t100_msg INTO DATA(lx_t100_msg).

  WRITE: / lx_t100_msg->get_text( ).

ENDTRY.

 

Following points describes briefly the coding steps.

 

StepDescription
Create FastRWebConnector instance

A FastRWebConnector instance is created by creating a new instance of class ZZ_CL_FASTRWEB_CONNECTOR. Mandatory arguments are the result type, the destination and the R script path.

 

For the result type there are two options:

  • ZZ_IF_FASTRWEB_CONNECTOR=>MC_RESULT_TYPE_JSON: The result returned from the R script has to be interpreted as JSON string.
  • ZZ_IF_FASTRWEB_CONNECTOR=>MC_RESULT_TYPE_IMAGE: The result returned has to be interpreted as binary string, no JSON transformation is done in that case.

 

The destination identifies the RFC destination which points to the Rserve web server.

 

The R script path parameter defines the path to the R script and the name of the R script (w/o file extension). The path is relative to the web folder defined for FastRWeb. "/R/test" means, that a R script file "test.R" in folder "R" within the web folder has to be used.

Setting of input parametersInput parameters are transferred as key/value pairs to the connector. This allows a flexible number of parameters. The "key" attribute has to be set to the parameter name of a parameter of the "run" function in the R script. The "value" attribute has to be supplied with a reference of a variable (e.g. structure, internal table) defined in the ABAP coding. It has to be considered that the field names of e.g. a structure needs to be used in the R script to asccess the fields.
Setting the result parameter referenceAt the moment the adapter supports one result parameter identified by key ZZ_IF_FASTRWEB_CONNECTOR=>MC_RESULT_KEY in the result key/value parameter. The value attribute has to be set to a reference of a variable fitting the result type of the R script. Assuming as value a reference with fields "VAL1" and "VAL2" is set, the R script has to return a JSON value with the attributes "VAL1" and "VAL2".
Execute R scriptTo call the R script, method EXECUTE_SCRIPT of the FastRWeb Connector instance has to be called.

 

R Script parameter handling

Parameters are transferred serialized as JSON string via URL parameters to the R script. To be able to access the data in the R script, the JSON string has to be transformed to a R data format. The Conversion is done using the R library jsonlite which allows transforming from and to JSON strings. To be able to use the package, it has to be installed using install.packages("jsonlite"). In the script to be used the library needs to be loaded by statement library("jsonlite"). Transforming data from a JSON string to a R list is done using function "fromJSON". Function "toJSON" transforms a R list to a JSON string. This function is used to prepare the result data to return it to the ABAP caller (except for plots).

 

Transfer parameters to R script

The following example describes how an internal ABAP table transferred as JSON string in an URL parameter is accessed in a R script.

 

ABAP internal table

C1C2C3
100101Test 1
200201Test 2
300301Test 3

 

With the ABAPtoJSON functionality used by the FastRWebConnector implementation, the internal table is converted to following JSON string.

 

"DATA": [

  { "C1": 100, "C2": 101, "C3": "Test 1" },

  { "C1": 200, "C2": 201, "C3": "Test 2" },

  { "C1": 300, "C2": 301, "C3": "Test 3" }

]

 

Within the R script the JSON string is converted to a R list using function "fromJSON".

 

input <- fromJSON(inputParameter)

 

The columns of the list can be accessed like following. It has to be considered that the FastRWebConnector intorduces the "DATA" identifier. This is necessary as additional identifier required by the ABAPtoJSON functionality.

 

input$DATA$C1

input$DATA$C2

input$DATA$C3

 

Return result from R script

Returning data from a R script is done as JSON string too (again except for plots). The result data has to be transfomred to a list and then the list has to be transformed with function "toJSON" to a JSON string. Function "done" sets in the R script the return value. It has to be considered that the ABAP variable for the result needs to have the same structure than the R list. That is necessary to receive the data in ABAP and successfully transform it from a JSON string to the ABAP variable.

 

jsonString <-> toJSON(dataList)

done(jsonString, cmd = "html", type = "application/json")

 

Examples

The following examples can be found at GitHub. Beside the ABAP coding, the R script coding is contained in the files too (commented out at the bottom of the files).

 

k-Means clustering of customer data

The first example shows a simple k-Means clustering for customers based on their Life Spend, News Spend, Income and Loyalty. The example is the same as used by the SAP HANA Academy to demonstrate the k-Means algorithm implemented in SAP HANA PAL (test data for that can be found at GitHub - saphanaacademy/PAL: Predictive Analysis Library).

 

The complete ABAP coding can be watched at FastRWebABAPConnector/ZZ_TEST_FASTRWEBCON_KMEANS.abap · GitHub.

 

The R script looks like following.

 

run <- function(settings, customer){

    # load jsonlite library for JSON data handling (i/o)

  library(jsonlite)

 

    # load amap library for k-Means algorithm

  library(amap)

 

    # convert input parameters in JSON to list

  customerData <- fromJSON(customer)

  settingsData <- fromJSON(settings)

 

    # remove ID for clustering

  inputWoID <- data.frame(lifespend=customerData$DATA$LIFESPEND,

                          newspan=customerData$DATA$NEWSPEND,

                          income=customerData$DATA$INCOME,

                          loyalty=customerData$DATA$LOYALTY)

 

    # k-Means execution; no. of clusters set via parameter, max 100 iterations,

  # Euclidean method

  resultKMeans <- Kmeans(inputWoID,

                         centers=settingsData$DATA$CENTERS,

                         iter.max=100,

                         method="euclidean")

 

    # combine customer information with clusters

  customerAssignedToCluster <- data.frame(ID=customerData$DATA$ID,

   CLUSTER=resultKMeans$cluster)

 

    # convert result data frame to JSON

  customerAssignedToClusterRoot <- list(DATA=customerAssignedToCluster)

  resultJSON <- toJSON(customerAssignedToClusterRoot)

 

  done(resultJSON, cmd = "html", type = "application/json")

}

 

The example program simply displays the customers with the calculated cluster ID.

03_example_1_output.png

 

Plotting

The second example (FastRWebABAPConnector/ZZ_TEST_FASTRWEBCON_PLOT.abap · GitHub) shows how a simple plot is created. The visualization of the plot image in UI5 and Webdynpro would be easy, so the example displays the image on a classical dynpro screen which is a bit more "complicated" (screen definition and GUI status are not included in the Github repository).

 

04_example_2_plot.png

 

Conclusion

With the usage of available open source components and a simple ABAP coding it is possible to use R scripts directly from ABAP. Customers w/o SAP HANA also have a chance to do lightweight statistical calculations and plotting with R without a complicated setup. Because with NW 7.50 the improved Push Channels with TCP support were released, the next step is to evaluate if it is possible to connect directly to the Rserve TCP/IP server, to be able to remove the HTTP component to create a slightly performance improvement.

How To Use SQLite with ADO via ODBC

$
0
0

Hello community,

 

one year ago I presented here the possibility how to export SAP table content to SQLite containers. One way is via a COM library which is a wrapper around a few functions of the SQLite library. This library has only one purpose, to export SAP table content easily. Recently reached me a few emails with the suggestion to extend the COM library, it should be possible to execute queries and handle the result. I thought about it and came to the conclusion that this is not necessary because you can use the full bandwith with ActiveX Data Objects (ADO) and Open Database Connectivity (ODBC).

 

To use SQLite via ODBC you must install a special driver. You can find a very good one here, it is free and released under BSD-type license. Now you can use SQLite databases with ABAP.

 

Here an example how to create and use an SQLite database:

 

"-Begin-----------------------------------------------------------------

Report ZODBC_SQLITE.

 

  "-Constants-----------------------------------------------------------

    Constants adUseClient Type i Value 3.

 

  "-Variables-----------------------------------------------------------

    Data oCon Type OLE2_OBJECT.

    Data oRecSet Type OLE2_OBJECT.

    Data oFields Type OLE2_OBJECT.

    Data oField Type OLE2_OBJECT.

    Data cntRec Type i.

    Data cntFields Type i.

    Data sSQL Type String.

    Data i Type i.

    Data j Type i.

    Data nameField Type String.

    Data valueField Type String.

 

  "-Main----------------------------------------------------------------

    Create Object oCon 'ADODB.Connection'.

    If sy-subrc <> 0 Or  oCon-Handle <= 0 Or oCon-Type <> 'OLE2'..

      Exit.

    EndIf.

    Set Property Of oCon 'CursorLocation' = adUseClient.

    Call Method Of oCon 'Open' Exporting

      #1 = 'DRIVER=SQLite3 ODBC Driver;Database=C:\Dummy\MyDb.db3;'.

 

    sSQL = 'DROP TABLE tblTest'.

    Call Method Of oCon 'Execute' Exporting #1 = sSQL.

 

    sSQL = 'CREATE TABLE tblTest(ID INTEGER PRIMARY KEY, NAME VARCHAR(40))'.

    Call Method Of oCon 'Execute' Exporting #1 = sSQL.

 

    i = 1.

    While i <= 16.

      sSQL = 'INSERT INTO tblTest VALUES(' && i && ', ''Name' && i && ''')'.

      Call Method Of oCon 'Execute' Exporting #1 = sSQL.

      i = i + 1.

    EndWhile.

 

    sSQL = 'SELECT * FROM tblTest'.

    Call Method Of oCon 'Execute' = oRecSet Exporting #1 = sSQL.

    Get Property Of oRecSet 'RecordCount' = cntRec.

    i = 1.

    While i <= cntRec.

      Get Property Of oRecSet 'Fields' = oFields.

      Get Property Of oFields 'Count' = cntFields.

      j = 0.

      While j <= cntFields - 1.

        Get Property Of oFields 'Item' = oField Exporting #1 = j.

        Get Property Of oField 'Name' = nameField.

        Get Property Of oField 'Value' = valueField.

        Write: / nameField, ` `, valueField.

        j = j + 1.

      EndWhile.

      Call Method Of oRecSet 'MoveNext'.

      i = i + 1.

    EndWhile.

 

    Call Method Of oCon 'Close'.

    Free Object oCon.

 

"-End-------------------------------------------------------------------

 

It is not necessary to build another library, with the existing possibilities like ADO and ODBC you can connect and use many different databases of different manufacturers with ABAP.

 

Enjoy it.

 

Cheers

Stefan

How To Activate Security Audit Log On The ABAP Trial System To Monitor RFC Calls

$
0
0

Hello community,

 

in a few cases I use an ABAP trial system to experiment. Today I want to test the Security Audit Log to monitor RFC calls, but the analysis of Security Audit Log (SM20) doesn't work on the trial system. Then I debugged the program SAPMSM20 and detect that the function module RSAU_READ_FILE is called with a destination and here I get a system failure, incomplete logon data. I read here in the SCN about the error which is based on a system copy. So I checked the TAC secstore and found the reason.

001.JPG

Because of the system copy are two entries in the secure store disabled. After I delete the two entries the analysis of the Security Audit Log works as expected and all RFC calls have been logged.

 

You can find more information about the Security Audit Log here.

 

Cheers

Stefan

Create an IDoc programmatically - Easy solution

$
0
0

I was new to IDocs. A recent assignment forced me to learn it. I realized that certain portions of Idoc creation could be easily programmed. So, explored a bit and wrote the code to auto-generate them. It worked like a charm. The code (or report: zzz_create_idoc_wizard) is pasted below. Enjoy

 

The below report has 5 mandatory parameters. Refer the comments against each of the parameters. Key in valid inputs and execute the report. (Based on your logged on SAP GUI security settings, you may get a security popup to take your confirmation to create/update a file in your local system. Just confirm by clicking 'Allow' or 'OK' button). The output of this report is a text file that gets saved in the path mentioned under parameter m_path. Copy the entire content of this text file. This is it. You can directly paste this 'ready-to-use code' either into a new report or a function module or a subroutine or a class-method. (Isn't it cool? )

 

In the auto generated text file, refer the comments mentioned. (By default, I have set the value to 'X'. You can either use this defaulted value for testing purposes. For productive use, replace the defaulted values with your own custom SELECT SQLs or custom logic to populate the segments' internal tables of your IDoc). Save and activate this new code. You are ready. The possible limits (max and min limit for each segment is also mentioned as comments in the code). This will be handy while preparing the internal tables for each segment of the IDoc.

 

Both 'basic' and extended' IDoc types are supported. This saves tons of coding time of developers who intend to write, test and rewrite iDocs.

The developer only needs to add the relevant functional/business logic under the specific commented sections of the code in reference to the productive usage of the IDoc (which of course cannot be automated. Are you crazy? )

 

IDoc.JPG

 

REPORT  zzz_create_idoc_wizard.
PARAMETERS: m_obj    TYPE edi_idcobj    OBLIGATORY. "Existing IDoc Object Name
PARAMETERS: m_mestyp TYPE edidc-mestyp  OBLIGATORY. "Message Type
PARAMETERS: m_rcvprt TYPE edidc-rcvprt  OBLIGATORY. "Partner Type of Receiver
PARAMETERS: m_rcvprn TYPE edidc-rcvprn  OBLIGATORY. "Partner Number of Receiver
PARAMETERS: m_path   TYPE rlgrap-filename OBLIGATORY DEFAULT 'C:\temp\idoc.txt'. "Local folder path to save the result or output file
AT SELECTION-SCREEN ON VALUE-REQUEST FOR m_path.   DATA: lv_path TYPE string.   CALL METHOD cl_gui_frontend_services=>directory_browse     EXPORTING       window_title    = 'Select Directory'     CHANGING       selected_folder = lv_path     EXCEPTIONS       cntl_error      = 1.   CALL METHOD cl_gui_cfw=>flush     EXCEPTIONS       cntl_system_error = 1       cntl_error        = 2.   m_path = lv_path && '\idoc.txt'.
START-OF-SELECTION.
* validate input   DATA l_attributes TYPE edi_iapi01.   CALL FUNCTION 'IDOCTYPE_EXISTENCE_CHECK'     EXPORTING       pi_idoctyp    = m_obj     IMPORTING       pe_attributes = l_attributes     EXCEPTIONS       OTHERS        = 1.   IF l_attributes IS INITIAL.     MESSAGE 'Invalid object' TYPE 'S' DISPLAY LIKE 'E'. EXIT.   ENDIF.
* process   DATA: lt_code TYPE TABLE OF string.   DATA: ls_code LIKE LINE OF lt_code.   ls_code = `**** Wizard generated code to create IDoc ` && m_obj && ` ****`.   APPEND ls_code TO lt_code.   APPEND INITIAL LINE TO lt_code.   APPEND 'DATA: control_record LIKE edidc.' TO lt_code.   APPEND 'DATA: i_communication LIKE edidc OCCURS 0 WITH HEADER LINE,' TO lt_code.   APPEND '      lt_data LIKE edidd OCCURS 0 WITH HEADER LINE,' TO lt_code.   APPEND '      ls_data LIKE LINE OF lt_data.' TO lt_code.   APPEND INITIAL LINE TO lt_code.   APPEND '**** Set the control record details' TO lt_code.   ls_code = 'control_record-idoctp = ''' && m_obj && '''.'.       APPEND ls_code TO lt_code.   ls_code = 'control_record-mestyp = ''' && m_mestyp && '''.'.  APPEND ls_code TO lt_code.   ls_code = 'control_record-rcvprt = ''' && m_rcvprt && '''.'.  APPEND ls_code TO lt_code.   ls_code = 'control_record-rcvprn = ''' && m_rcvprn && '''.'.  APPEND ls_code TO lt_code.   APPEND INITIAL LINE TO lt_code.   APPEND '**** Logic to populate internal table LT_DATA[] ****' TO lt_code.   PERFORM custom_logic USING m_obj CHANGING lt_code.   APPEND INITIAL LINE TO lt_code.   APPEND '**** End of logic to populate internal table LT_DATA[] ****' TO lt_code.   APPEND INITIAL LINE TO lt_code.   APPEND 'CHECK LT_DATA[] IS NOT INITIAL.' TO lt_code.   APPEND INITIAL LINE TO lt_code.   APPEND '**** IDoc creation' TO lt_code.   APPEND '    CALL FUNCTION ''MASTER_IDOC_DISTRIBUTE''' TO lt_code.   APPEND '      EXPORTING' TO lt_code.   APPEND '        master_idoc_control            = control_record' TO lt_code.   APPEND '      TABLES' TO lt_code.   APPEND '        communication_idoc_control     = i_communication' TO lt_code.   APPEND '        master_idoc_data               = LT_DATA' TO lt_code.   APPEND '      EXCEPTIONS' TO lt_code.   APPEND '        error_in_idoc_control          = 1' TO lt_code.   APPEND '        error_writing_idoc_status      = 2' TO lt_code.   APPEND '        error_in_idoc_data             = 3' TO lt_code.   APPEND '        sending_logical_system_unknown = 4' TO lt_code.   APPEND '        OTHERS                         = 5.' TO lt_code.   APPEND '    IF sy-subrc <> 0.' TO lt_code.   APPEND '      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno' TO lt_code.   APPEND '              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.' TO lt_code.   APPEND '    ELSE.' TO lt_code.   APPEND '      LOOP AT i_communication.' TO lt_code.   APPEND '        WRITE: ''IDOC GENERATED'', i_communication-docnum. "check in tcode: WE05' TO lt_code.   APPEND '      ENDLOOP.' TO lt_code.   APPEND '      COMMIT WORK.' TO lt_code.   APPEND '    ENDIF.' TO lt_code.   DATA lv_path TYPE string.   lv_path = m_path.   CALL METHOD cl_gui_frontend_services=>gui_download     EXPORTING       filename = lv_path       filetype = 'DAT'     CHANGING       data_tab = lt_code[].   CALL METHOD cl_gui_frontend_services=>execute     EXPORTING       document               = lv_path  " m_path+Name to Document     EXCEPTIONS       cntl_error             = 1       error_no_gui           = 2       bad_parameter          = 3       file_not_found         = 4       path_not_found         = 5       file_extension_unknown = 6       error_execute_failed   = 7       synchronous_failed     = 8       not_supported_by_gui   = 9       OTHERS                 = 10.   IF sy-subrc <> 0.     "   do nothing   ENDIF.
*&---------------------------------------------------------------------*
*&      Form  GENERATE_LINES
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*      -->P_OBJ  text
*      <--P_LT_CODE  text
*----------------------------------------------------------------------*
FORM custom_logic  USING    p_obj LIKE m_obj                      CHANGING p_lt_code LIKE lt_code.   DATA l_idoctyp TYPE edi_idoctp.   DATA g_idoctyp_attr TYPE edi_iapi01.   DATA :         gt_idocsyn      LIKE edi_iapi02   OCCURS 20 WITH HEADER LINE,         gt_prev_idocsyn LIKE edi_iapi02   OCCURS 20 WITH HEADER LINE,         gs_prev_idocsyn LIKE LINE OF gt_prev_idocsyn.   DATA: gt_tnode           LIKE snodetext    OCCURS 20 WITH HEADER LINE,         gt_attr            LIKE sed5attr     OCCURS 20 WITH HEADER LINE,         gs_attr            LIKE LINE OF gt_attr.
* read basis type   l_idoctyp = p_obj.   CALL FUNCTION 'IDOCTYPE_READ'     EXPORTING       pi_idoctyp    = l_idoctyp     IMPORTING       pe_attributes = g_idoctyp_attr     TABLES       pt_syntax     = gt_idocsyn       pt_pre_syntax = gt_prev_idocsyn.   DATA lv_variable TYPE string VALUE 'DATA : LT_& TYPE TABLE OF &, LS_& LIKE LINE OF LT_&.'.   DATA lv_variable_temp TYPE string.   LOOP AT gt_idocsyn INTO gs_prev_idocsyn.     lv_variable_temp = lv_variable.     REPLACE ALL OCCURRENCES OF '&' IN lv_variable_temp WITH gs_prev_idocsyn-segtyp.     APPEND lv_variable_temp TO p_lt_code.   ENDLOOP.   CALL FUNCTION 'CONVERT_IDOC_SYNTAX_TO_TREE'     EXPORTING       pi_idoctyp      = l_idoctyp       pi_descrp       = ''" g_idoctyp_attr-descrp       pi_e2display    = ''       pi_e2segrel     = ''     TABLES       lt_idocsyn      = gt_idocsyn       lt_prev_idocsyn = gt_prev_idocsyn       lt_tree         = gt_tnode       lt_attr         = gt_attr.   LOOP AT gt_attr INTO gs_attr.     APPEND INITIAL LINE TO lt_code.     lv_variable_temp = `**** Process segment: ` && gs_attr-segtyp.     APPEND lv_variable_temp TO lt_code.     lv_variable_temp = 'REFRESH LT_&. CLEAR LT_&[]. CLEAR LS_&.'.     REPLACE ALL OCCURRENCES OF '&' IN lv_variable_temp WITH gs_attr-segtyp.     APPEND lv_variable_temp TO lt_code.     DATA lt_ddic_info TYPE  ddfields.     DATA ls_ddic_info LIKE LINE OF lt_ddic_info.
*get ddic fields     CALL FUNCTION 'CATSXT_GET_DDIC_FIELDINFO'       EXPORTING         im_structure_name = gs_attr-segtyp       IMPORTING         ex_ddic_info      = lt_ddic_info       EXCEPTIONS         failed            = 1         OTHERS            = 2.     IF sy-subrc <> 0.       " do nothing     ENDIF.     APPEND INITIAL LINE TO lt_code.     SHIFT gs_attr-occmax LEFT DELETING LEADING '0'.     lv_variable_temp = `**** Write your custom logic here. Note that the maximum limit for segment ` && gs_attr-segtyp && ` = ` && gs_attr-occmax.     APPEND lv_variable_temp TO lt_code.     IF gs_attr-occmax > 1.       lv_variable_temp = '**** You may cutom code your logic (or copy by referring below statements) for a maximum limit of #' && gs_attr-occmax && ' times'.       APPEND lv_variable_temp TO lt_code.     ENDIF.     LOOP AT lt_ddic_info INTO ls_ddic_info.       CASE ls_ddic_info-datatype.         WHEN 'CHAR'. lv_variable_temp = 'X'.         WHEN ''. "enhance for other types: I, P, date, time, etc         WHEN OTHERS. lv_variable_temp = 'X'. "default 'X' should work for most random cases       ENDCASE.       lv_variable_temp = 'LS_' && gs_attr-segtyp && '-' && ls_ddic_info-fieldname && ' = ''' && lv_variable_temp && '''.'.       APPEND lv_variable_temp TO lt_code.     ENDLOOP.     IF lt_ddic_info IS NOT INITIAL.       lv_variable_temp = 'APPEND LS_& TO LT_&.'.       REPLACE ALL OCCURRENCES OF '&' IN lv_variable_temp WITH gs_attr-segtyp.       APPEND lv_variable_temp TO lt_code.       APPEND INITIAL LINE TO lt_code.     ENDIF.     lv_variable_temp = 'LOOP AT LT_& INTO LS_&.'.     REPLACE ALL OCCURRENCES OF '&' IN lv_variable_temp WITH gs_attr-segtyp.     APPEND lv_variable_temp TO lt_code.     lv_variable_temp = `  LS_DATA-segnam = '&'. LS_DATA-sdata = LS_&. APPEND LS_DATA TO LT_DATA.`.     REPLACE ALL OCCURRENCES OF '&' IN lv_variable_temp WITH gs_attr-segtyp.     APPEND lv_variable_temp TO lt_code.     APPEND 'ENDLOOP.' TO lt_code.   ENDLOOP.
ENDFORM.                    " GENERATE_LINES

the Function to Setting BAPI update flags

$
0
0

    When we call the BAPI , Example to create or modify a meterial data . Often face dozens or even hundreds of fields corresponding to "BAPIUPDATE".The following function codes can be done will not emty field of the same name "BAPIUPDATE" fill to "X".

 

 

CODE 



 FUNCTION ZBAPI_UPDATEFLAG_SET_X.
 *"----------------------------------------------------------------------
 *"*"本地接口: 
 *"  IMPORTING
 *"     VALUE(INPUT)
 *"     VALUE(FLAG) DEFAULT 'X'
 *"  EXPORTING
 *"     REFERENCE(OUTPUT)
 *"  EXCEPTIONS
 *"      PARAMETER_NOT_STRUCTURE
 *"----------------------------------------------------------------------
 *" Author : 高巍巍
 *"---------------------------------------------------------------------- 
   TYPE-POOLS: sydes.   DATA     : lr_structure  TYPE REF   TO cl_abap_structdescr"cl_abap_typedescr     , ls_component  TYPE          abap_compdescr     .   FIELD-SYMBOLS       : <fs_val>       , <fs_flg>       .   lr_structure ?= cl_abap_typedescr=>describe_by_data( output  ).   CHECK lr_structure IS NOT INITIAL.   IF lr_structure->kind NE cl_abap_typedescr=>kind_struct.     RAISE parameter_not_structure.   ENDIF.   LOOP AT lr_structure->components INTO ls_component .     CHECK ls_component-type_kind = 'C' AND           ls_component-length    = 1.     ASSIGN COMPONENT ls_component-name OF STRUCTURE input  TO <fs_val>.     CHECK <fs_val> IS ASSIGNED.     ASSIGN COMPONENT ls_component-name OF STRUCTURE output TO <fs_flg>.     CHECK <fs_flg> IS ASSIGNED.     IF <fs_val> IS NOT INITIAL AND        <fs_flg> IS     INITIAL.       <fs_flg> = flag.     ENDIF.     UNASSIGN : <fs_val>,<fs_flg>.   ENDLOOP.
 ENDFUNCTION.

 

 

Example :

 

DATA  :  LS_CLIENTDATA   LIKE BAPI_MARA   ,  LS_CLIENTDATAX  LIKE BAPI_MARAX   .
CALL FUNCTION 'ZBAPI_UPDATEFLAG_SET_X'    EXPORTING        INPUT             = LS_CLIENTDATA    IMPORTING        OUTPUT            = LS_CLIENTDATAX    EXCEPTIONS        PARAMETER_NOT_STRUCTURE = 1        OTHERS            = 2.

 

 

 

 

 

 

 
































ABAP Channels Examples

$
0
0

As I started to implement the ABAP Channels with our colleagues I also have tried to implement different test applications and show cases to check and demonstrate the behavior of the ABAP Channels in different contexts. This comprises the usage in UI5/Fiori programming model, Web Dynpro, BSP, and WebGUI, as well as collaboration, "real-time", and throughput aspects. The result of these efforts was that some of those applications has been integrated as "simple" example application in  the ABAP Channels package "SAPC_EXAMPLES" to be able to use them as show case application for different occasions, e.g. TechEds and the like. Some of those examples are shown in the YouTube video "ABAP Channels - Real time eventing in ABAP".

 

In this blog we present some of the ABAP Channels show cases, which were delivered with SAP Netweaver ABAP 740 SP05 onward. The example applications are kept very simple and do not necessarily fulfill all the software requirement aspects for business applications. Thus these examples are not aimed and released for productive usage and we do not provide any support regarding any issues raised during execution in the applications! The goal of the provided example applications is to give an idea how the ABAP Channel technology, especially based on collaboration scenario, could be used to realize different use cases.

 

All these applications require an HTML5 based browser that supports WebSocket specification RFC 6455. A list of supported browsers are provided by http://caniuse.com/websockets. Furthermore it might be that some of the applications run only on certain browser types, e.g. only on Chrome.

 

Example Applications Since 740 SP05

Following example applications are available since 740 SP05:


  • Ping: a simple bi-direction push application. The application is running in browser and exchanges text messages between browser windows and ABAP reports.

 

Prerequisite: In the transaction SICF the following service paths has to be activated before:

    • /sap/bc/apc_test/ping: provides a web page for publishing and receiving of text messages.
    • /sap/bc/apc/sap/ping: provides ABAP Push Channel application for the WebSocket connection used to publish and receive text messages.

 

The following ABAP reports can be used to exchange messages between browser windows and ABAP reports:

    • RS_AMC_SEND_MESSAGE: the report (with its default parameter settings) sends messages to the browser window using AMC Channel.
    • RS_AMC_RECEIVE_MESSAGE: the report (with its default parameter settings) receives messages that have been sent either from the browser or the ABAP report. For message reception the ABAP report provides the following options:
      • Option "Wait Statement": receive messages via WAIT statement.
      • Option "List processing": receive messages via list processing.

 

The URL for the Ping application is http(s)://<host.domain>:<port>/sap/bc/apc_test/ping. Alternatively, the service path /sap/bc/apc_test/ping can be launched in the web browser via transaction SICF; see section "Execution of Services in SICF" blelow.

 

Figure 1 shows how a message published in a web browser is received in another web browser and SAP GUI session. Figure 2 shows how a message published in SAP GUI session is received in another SAP GUI session and web pages.


ping_browser_e.PNG

Figure 1: Sending messages from a browser (HTML5 UI) to other browsers or ABAP sessions.


ping_report_e.png

Figure 2: Sending messages from an ABAP sessions to other browsers (HTML5 UI) and ABAP sessions.

 

  • Ping Pong: an interactive table tennis (pong) game.


Prerequisite: the application consist of the following elements:

    • Playing field: a playing field, which is executed as an HTML5 application in the browser. The URL for the playing field is http(s)://<host.domain>:<port>/sap/bc/apc_test/ping_pong/game. Alternatively, the service path /sap/bc/apc_test/ping_pong/gamecan be launched in the web browser via transaction SICF; see section "Execution of Services in SICF" blelow.


    • Players: players can either run in browser or in ABAP report.
      • Player running in browser: the URL for ping pong player is http(s)://<host.domain>:<port>/sap/bc/apc_test/ping_pong/player. In the browser page, you can choose the player, i.e, Player1 or Player 2.
      • Player running as ABAP report: the report RS_APC_PING_PONG provides a player screen when executing the report via transaction SA38 or SE38. The player can select to attend either as Player1 or as Player2.


Restrictions: This simple sample application allows one active match per system and client only.

ping_pong_e.PNG

Figure 3: Playing table tennis including playing field and player 1 in browser and player 2 in SAP GUI.



Example Applications Since 740 SP08

With 740 SP08 we also have integrated the SAP message format "Push Channel Protocol" (PCP) in ABAP Push Channels and provided a JavaScript library as well as a UI5 library. PCP is WebSocket subprotocol (registered at IANA); it is the preferred protocol for SAP push applications. The JavaScript and UI5 libraries are especially designed for SAP HTML browser based UI technologies, i.e. UI5/Fiori, Web Dynpro, BSP/CRM UI, and WebGUI. The YouTube video "ABAP Channels - Real time eventing in ABAP" demonstrates these examples as well.


Following example applications are available since 740 SP08:


  • ABAP Online Community (AOC aka Palavar): the application provides simple instant messaging (similar to WhatsApp). This can be used not only for exchanging messages but also for sharing pictures and documents. The AOC exists in two different UI technologies, namely UI5/Fiori and Web Dynpro.

In AOC the interaction between users are controlled by the term "Room". Only users belonging to a "Room" can interact with each other. There exists two types of rooms, "Public Rooms" and "Own/Permitted Rooms". Whereas "Public Rooms" are accessible for any user, the access to the "Own/Permitted Rooms" is only permitted to the members of the room and controlled by access control lists. The access control list per room can be maintained manually by assigning valid users in the respective system and client. All room ids starting with the prefix "public" (case insensitive) belong to "Public Rooms" and hence are publicly accessible.

 

Important remarks: whereas the text messages are immediately published in the respective room and not persisted in the database table, shared documents, i.e. any uploaded picture or document, are persisted on database and a reference is pushed to the room members. Each uploaded document is checked via virus scanner (with virus scan profile /SIHTTP/HTTP_UPLOAD); an ABAP dump could arise if the virus scan check fails. Since there exist no "garbage collector" for the database table entries, this could lead to table space issues and also security issues (as the published documents may contain security relevant information). For cleaning up the affected table entries there exists the static method CL_ABAP_ONLINE_COMMUNITY_UTIL=>CLEANUP_SHARED_DOCUMENTS (or a customized copy of it), which could be used to cleanup the entries older than 1 hour. This could be scheduled as a periodic batch job.


    • UI5/Fiori version of AOC: the URL for this version of AOC application is http(s)://<host.domain>:<port>/sap/bc/ui5_ui5/sap/aoc/index.html. According to my present tests (at the time this blog has been written), this version works fine under Chrome and iPhone/iPad using mobile Safari. The upload function provided in the rooms does not work in IE and Firefox, but the messaging works fine. It is also nice to see how the exchange of messages and pictures works in a local network using mobile devices, e.g on iPhone try the voice recognition!
      • Features:
        • Entering/Leaving a room: As soon as a member enters a room or actively leaves the room, i.e. using "switch icon", the member list gets updated.
        • Members: room members can see the present activity status ("Online" or "typing") of all room members.


Prerequisite: in the transaction SICF following service paths has to be activated before:

        • /sap/bc/ui5_ui5/sap/aoc: provides the Fiori page for AOC application.
        • /sap/bc/apc/sap/abap_online_community: provides ABAP Push Channels application for the WebSocket connection used for message exchange.
        • /sap/bc/apc_test/abap_online_com: provides the HTTP service for exchanging documents.

aoc_ui5_1_e.PNG

Figure 4: AOC UI5/Fiori start page.


aoc_ui5_2.PNG

Figure 5: AOC UI5/Fiori room page.


    • Web Dynpro version of AOC: the URL for this version of AOC application is http(s)://<host.domain>:<port>/sap/bc/webdynpro/sap/abap_online_community. This version of the AOC provides instant messaging features similar to the UI5/Fiori version. The difference is the UI technology (Web Dynpro) and its session handling based on stateful HTTP communication (be aware of session timeouts !).

 

Prerequisite: in the transaction SICF following service paths has to be activated before:

      • /sap/bc/webdynpro/sap/abap_online_community: provides the Web Dynpro application.
      • /sap/bc/apc/sap/abap_online_community: provides ABAP Push Channels application for the WebSocket connection  for message exchange.
      • /sap/bc/apc_test/abap_online_com: provides the HTTP service for exchanging documents.

aoc_webdynpro_1_e.PNG

Figure 4: AOC Web Dynpro start page.

 

aoc_webdynpro_2_n.PNG

Figure 5: AOC Web Dynpro room page.


Sohbat based applications:

The aim of the Sohbat framework (Sohbat means in Persian/Farsi language "speak/conversation")was to establish a "simple rapid prototyping framework" for implementation of ABAP Channels show cases. It provides simple APIs based on database CRUD (Create/Read/Update/Delete) and publish-subscribe pattern.


Following examples are based on the Sohbat framework:


  • Sohbat Slider: demonstrates the "real-time" power of ABAP Channels (by the way my favorite show case). The abstract idea is to provide a test application that takes use of Fiori and SapPcpWebSocket libraries to visualize a simple business object (a database table) consisting of the attributes "First Name", "LastName", and "Performance". Furthermore, the UI model and view should automatically be updated when any changes on the business object (database table) takes place in the backend system. In short, the goal is to eliminate the refresh button in the UI! The replacement of the refresh button depends on the UX expectation. In this example we use two patterns, namely notification bar and auto refresh.

 

The URL for the Sohbat Slider application is http(s)://<host.domain>:<port>/sap/bc/bsp/sap/sohbat_slider/index.html. Alternatively, the service path /sap/bc/bsp/sap/sohbat_slidercan be launched in the web browser via transaction SICF; see section "Execution of Services in SICF" blelow.


Prerequisite: in the transaction SICF the following service paths has to be activated before:

    • /sap/bc/bsp/sap/sohbat_slider: provides the Fiori UI application.
    • /sap/bc/apc/sap/sohbat: provides the ABAP Push Channels application for the WebSocket connection. It uses the PCP subprotocol for exchanging the CRUD-like messages.

 

sohbat_slider_e.png

Figure 6: Sohbat Slider page.


  • Sohbat Video: is a prototype application for sharing videos (actually picture sequences) between users. It demonstrates how fast the ABAP engine can handle a large number PCP messages with encapsulated binary data. The web client is based on SapPcpWebSocket in UI5. My observation was that with increasing number of web clients the bottleneck was the rendering engine of underlying browsers and not the ABAP engine (just check the transaction SM50 during the video transfer!).


The URL for the Sohbat Slider application is http(s)://<host.domain>:<port>/sap/bc/bsp/sap/sohbat_video/index.html. Alternatively, the service path /sap/bc/bsp/sap/sohbat_videocan be launched in the web browser via transaction SICF; see section "Execution of Services in SICF" blelow. After launching the application you have to accept the access permission to your webcam. The popup which requires the permission in Firefox has the following shape:


palaver_video_firefox_popup.png

Figure 7: Popup screen for requesting access permission to connected Webcam device


  • Prerequisite: The Fiori page takes use of the getUserMedia API, i.e. "Capturing Audio and Video in HTML5". The list of supported browsers, e.g. Chrome and Firefox, can be checked under http://caniuse.com/#search=getusermedia. Furthermore in order to publish video, the PC/notebook has to have a functional webcam. For receiving and viewing the videos no webcam is needed and usually any browser, e.g. the one in your mobile device, can be used.


In the transaction SICF following service paths has to be activated before:

    • /sap/bc/bsp/sap/sohbat_video: provides the Fiori UI application.
    • /sap/bc/apc/sap/sohbat: provides the ABAP Push Channels application for the WebSocket PCP-based connection and message exchange.

 

sohbat_video_e.PNG

Figure 8: Sohbat Video page (video snapshot taken in our office in Walldorf).


Execution of Services in SICF

In general, a service URL, e.g., /sap/bc/apc_test/ping, can also be executed via transaction SICF of the corresponding application server. To do this choose the service path, e.g., /sap/bc/apc_test/ping, in the transaction SICF and choose the context menu function (right mouse button) "Service Test". Please note that in this case the default browser is used for the execution of the URL, which might not support WebSockets. Make sure that the URL is carried out in a suitable browser, such as Chrome.


Conclusion and outlook

The examples demonstrates the amazing potential of the ABAP Channels infrastructure for high-responsive and real-time UI applications. New use cases can be realized, which would not be possible using polling. The capability of the infrastructure of handling a high message throughput and the positive experience with this technology in different projects motivated us to go beyond. In NetWeaver 7.50 the ABAP Channels has been extended to support plain TCP/IP socket protocols, which are needed to directly connect industrial devices (e.g., Programmable Logic Controllers) to ABAP business applications. This builds the basis for our Industry 4.0 (Industrial Internet of Things) infrastructure in ABAP.




Viewing all 68 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>