This year, just a week before I’ve started my wonderful vacations in Barcelona and Alcúdia, I had again the pleasure to hold a session at SAP Inside Track Hamburg. Because I’m not able to provide the slides (I haven’t used any) I was asked to blog about it. (to satisfy someone: this means to “write a blog post” 😉 )

The Motivation

One of my current customers is implementing a new E-commerce shop and I’m responsible for the connection to the backend SAP ERP system. “Yea, again a SAP Gateway project” just came into my mind as soon as I’ve heard about it 🙂 A quick look into “System -> Status” and I realized that they are on ERP 6.0 Ehp 0 (Zero) -> no Gateway installed.

The Options

  1. upgrade the system to a higher Enhancement Package so SAP GW is part of the standard installation
  2. install SAP GW as Add-On
  3. something completely different

Option 1.) was completely out of budget. Sure, they have to do it sometimes in the near future, but not now and not for this reason.

For option 2.) a question came into my mind, which I was not able to answer: what happens in a later EHP upgrade, where SAP GW is part of the standard, if we already had installed SAP GW as Add-On? Will we get into trouble?

The Solution

If you know a bit of my background (I’m a little RESTifarian ), you will not be surprised that I’ve choosen ADL (Alternative Dispatcher Layer, by DJ Adams ) and zJSON (ABAP JSON document class, by me) to solve this problem. Open Source #ftw ! Links: see Appendix


SAP’s new claim is “SIMPLE”. And yes: ADL + zJSON is simple. It’s so simple, that I’m using it even for prototyping if SAP GW IS installed (because ie. the cleansing behind you is much easier).


Edit: please concider that you need an additional user license for the (anonymous) ICF user.


The Data

To make the demo a bit (more) interesting, I’ve used a DDL view instead of a table as data source:

@AbapCatalog.sqlViewName: ‘YSITHH_SO’

define view ysitHHSalesOrder as select from snwd_so as so

inner join snwd_bpa as bpa on so.buyer_guid = bpa.node_key {

  key so.so_id as id,

  bpa.bp_id as business_partner_id,

  bpa.company_name,

  substring( bpa.company_name, 1, 10 ) as company_short,

  case bpa.bp_role

    when ’01’ then ‘Customer’

    when ’02’ then ‘Supplier’

    else ‘undefined’

  end as business_partner_role,

  case so.billing_status

    when ‘ ‘ then ‘unpaid’

    else ‘paid’

  end as billing_status,

  @Semantics.currencyCode so.currency_code,

  @Semantics.amount.currencyCode: ‘currency_code’ so.gross_amount

}

(for documentation link on DDL sources and the new openSQL syntax, see Appendix)

Test report

DATA salesorders TYPE STANDARD TABLE OF ysithhsalesorder.

SELECT * FROM ysithhsalesorder

  INTO TABLE @salesorders.

cl_demo_output=>display( salesorders ).

Result

sitHH_1.PNG

The JSON document

To translate the data in JSON format I’ve used my JSON document class.

DATA salesorders TYPE STANDARD TABLE OF ysithhsalesorder.

SELECT * FROM ysithhsalesorder

  INTO TABLE @salesorders.

cl_demo_output=>display_json( zcl_json_document=>create_with_data( salesorders )>get_json( ) ).

(you’ve noticed the method chaining? I like it. But don’t overuse it, please)

Result

sitHH_6.PNG

The Call

Now to the REST call: the ADL implementation.

We have to create the REST dispatcher (or use an existing one) and the REST resource for the order data.

The Dispatcher

CLASS ysithh_dispatcher_test DEFINITION

  PUBLIC

  INHERITING FROM y_adl_disp_base

  FINAL

  CREATE PUBLIC .

  PUBLIC SECTION.

    METHODS if_http_extension~handle_request REDEFINITION.

  PROTECTED SECTION.

  PRIVATE SECTION.

ENDCLASS.

CLASS YSITHH_DISPATCHER_TEST IMPLEMENTATION.

  METHOD if_http_extension~handle_request.

    handler( p = ‘^/SalesOrder’ h = ‘YSITHH_SALESORDER_TEST’ ).

    dispatch( server ).

  ENDMETHOD.

ENDCLASS.

Don’t forget to enter the dispatcher class into the ICF path via transaction SICF

sitHH_2.PNG

sitHH_3.PNG

The Resource

CLASS ysithh_salesorder_test DEFINITION

  PUBLIC

  INHERITING FROM y_adl_res_base

  FINAL

  CREATE PUBLIC .

  PUBLIC SECTION.

    METHODS get

      IMPORTING matches TYPE stringtab.

  PROTECTED SECTION.

  PRIVATE SECTION.

ENDCLASS.

CLASS ysithh_salesorder_test IMPLEMENTATION.

  METHOD get.

    DATA salesorder TYPE STANDARD TABLE OF ysithhsalesorder.

    SELECT * FROM ysithhsalesorder

      INTO TABLE @salesorder.

    response->set_cdata( zcl_json_document=>create_with_data( salesorder )>get_json(  ) ).

    response->set_header_field(

      EXPORTING

        name = ‘Access-Control-Allow-Origin’    ” Name of the header field

        value = ‘*’    ” HTTP header field value

    ).

  ENDMETHOD.

ENDCLASS.

The Test

For a test of the service just call the resource in a browser of your choice: http://host:port/sap/bc/ysithh_test/SalesOrder

Viewed with Chrome plug-in “JSONview”

sitHH_4.PNG

The App

Now we are able to consume the data for example in an UI5 table.

index.html

<!DOCTYPE HTML>

<html>

<head>

<meta http-equiv=“X-UA-Compatible” content=”IE=edge”>

<meta http-equiv=‘Content-Type’ content=‘text/html;charset=UTF-8’/>

<script src=“resources/sap-ui-core.js”

id=“sap-ui-bootstrap”

data-sap-ui-libs=“sap.ui.commons”

data-sap-ui-theme=“sap_bluecrystal”>

</script>

<!– add sap.ui.table,sap.ui.ux3 and/or other libraries to ‘data-sap-ui-libs’ if required —>

<script>

sap.ui.localResources(“sithh_test”);

var view = sap.ui.view({id:“idmain1″, viewName:”sithh_test.main”, type:sap.ui.core.mvc.ViewType.XML});

view.placeAt(“content”);

</script>

</head>

<body class=“sapUiBody” role=”application”>

<div id=“content”></div>

</body>

</html>

main.view.xml


<core:View xmlns:core="sap.ui.core"
  xmlns:mvc="sap.ui.core.mvc"
  xmlns:commons="sap.ui.commons"
  xmlns:m="sap.m"
           xmlns="sap.ui.table"
  controllerName="sithh_test.main" xmlns:html="http://www.w3.org/1999/xhtml">
  <Table
  id="tt"
  rows="{/itab}"
  title="Table Example">
  <columns>
  <Column>
  <label>
  <commons:Label text="ID" />
  </label>
  <template>
  <commons:TextField value="{id}" />
  </template>
  </Column>
  <Column>
  <label>
  <commons:Label text="Company" />
  </label>
  <template>
  <commons:TextField value="{company_short}" />
  </template>
  </Column>
  <Column>
  <label>
  <commons:Label text="Role" />
  </label>
  <template>
  <commons:TextField value="{business_partner_role}" />
  </template>
  </Column>
  <Column>
  <label>
  <commons:Label text="Status" />
  </label>
  <template>
  <commons:TextField value="{billing_status}" />
  </template>
  </Column>
  <Column>
  <label>
  <commons:Label text="Currency" />
  </label>
  <template>
  <commons:TextField value="{currency_code}" />
  </template>
  </Column>
  <Column>
  <label>
  <commons:Label text="Value" />
  </label>
  <template>
  <commons:TextField value="{gross_amount}" />
  </template>
  </Column>
  </columns>
  </Table>
</core:View>







main.controller.js


sap.ui.controller("sithh_test.main", {
  onInit: function() {
  var oModel = new sap.ui.model.json.JSONModel(
  'http://se38-d7x-1.se38.local:8000/sap/bc/ysithh_test/SalesOrder'
  );
  sap.ui.getCore().setModel(oModel);
  },
});






The Result

sitHH_5.PNG

Appendix

If you wonder: SAP has changed the name of “SAP Netweaver Gateway”. It is now just “SAP Gateway”

ADL

Source: https://github.com/qmacro/ADL

Documentation: http://scn.sap.com/people/dj.adams/blog/2009/09/21/a-new-rest-handler-dispatcher-for-the-icf

JSON Document Class

Source: https://github.com/se38/zJSON/wiki/Usage-zJSON

Open UI5

http://sap.github.io/openui5/

DDL

http://scn.sap.com/community/abap/eclipse/blog/2014/02/04/new-data-modeling-features-in-abap-for-hana

New Open SQL Syntax

http://help.sap.com/abapdocu_740/en/index.htm?file=ABENNEWS-740_SP05-OPEN_SQL.htm

You can reach me via Twitter or G+

To report this post you need to login first.

9 Comments

You must be Logged on to comment or reply to a post.

    1. Uwe Fetzer Post author

      Hi Jeroen,

      yes of course. In the resource class you have the full access to the request object.

      If it is an HTTP GET you can read the field via method IF_HTTP_ENTITY~GET_FORM_FIELD( “billing_status”). For a POST request, you can read the body of the request (which hopefully contains JSON 😛 ).

      (0) 
  1. Gareth Ryan

    I was asked to blog about it. (to satisfy someone: this means to “write a blog post” 😉 )

    Ha – brilliant, I’m sure that someone will be pleased he’s got through to another person!

    Cheers,

    G.

    (0) 
  2. Raik Kulinna

    Hi Uwe, nice blog.


    Short feedback to all consulting companies that reads your blog: the license SAP Gateway for Consumer is not only the technical enablement to connect SAP to such a non-SAP web shop. It also contains the usage right for the web shop user (=end customer) to access indirectly SAP data without a Named User license. Several similar licenses includes similar usage rights for “consumers”. I don’t know the right license for your development. I personally think that it’s a good idea to check the final landscape upfront with the SAP sales contact responsible for the SAP back end or the partner management for consulting companies.


    See for example software use right:

    http://global.sap.com/corporate-en/our-company/agreements/western-europe/software-use-rights-agreements.epx


    See for example the partner program for OEM development: SAP Application Development Partner Center


    Regards,



    Raik

    as private reader of interesting technology blogs

    (0) 
    1. Uwe Fetzer Post author

      Hi Raik,

      thank you for the advice for the additional user license. I’ve added this hint to the blog (chapter “Solution”). In our project we already have the license because of an already existing shop solution.

      It also contains the usage right for the web shop user (=end customer) to access indirectly SAP data without a Named User license.

      Where do you have this information from? Do you have a link?

      (0) 
      1. Raik Kulinna

        Hi Uwe,

        You could see the exception of the named user for example in the SAP store -> Gateway for Consumer -> pricing. It is mentioned in the pricing section that Administrators and Developers need a Named User. That means that “consumers” doesn’t need an additional named user license while accessing SAP over this component. Other components like the SAP Mobile Platform for consumer have similar statement in the pricing section.

        https://store.sap.com/sap/cp/ui/resources/store/html/SolutionDetails.html?pid=0000009470&pcnty=US

        It is more clear in the SAP price list. That means that SAP sales should tell the correct answer in the context of the specific sales history of the customer.

        Sales should also answer if your shop solution license includes your “new” access described in the blog. A check is not possible without the exact license numbers and without your specific SAP sales contact.

        (0) 
        1. Uwe Fetzer Post author

          Got it now. But it doesn’t make a huge diffenerence whether I buy 75k SAP GW requests or a system user license (each around €400 / year if I remember correctly, but I may be wrong).

          Regarding my customer: I will not discuss license topics here on SCN (and yes, we have enough licenses, believe me 😉 ). Thank you though.

          (0) 
  3. Renald Wittwer

    HI Uwe,

    just used the described solution in a project. It runs out of the box!

    Brilliant!

    Thanks a lot to You and DJ. I owe you both at least a beer next time we see us.

    Regards

    Renald

    (0) 

Leave a Reply