Quantcast
Channel: SCN : Blog List - SAP Gateway
Viewing all 245 articles
Browse latest View live

Upcoming Webinars - Liberate your SAP Data with SAP NetWeaver Gateway

$
0
0

Liberate your SAP backend Data to Consume and Share Anywhere with SAP NetWeaver Gateway


Provide engaging experiences with customers, simplify interactions with partners, and improve productivity for your workers all with a flexible development platform. 


Dear Customer/Partner,

When it comes to accessing and using massive collections of data, address the critical issues head-on with SAP NetWeaver Gateway.  SAP NetWeaver Gateway liberates your
data so you can provide engaging experiences with customers, simplify interactions with partners and improve productivity for your workers. In this session, SAP Product Management experts will take you through how SAP NetWeaver Gateway provides ease of access, enterprise readiness, and simplified development that will transform your approach to connecting People, Data and Processes. Discover the latest features of the recently released SP08 and learn how key customers are using SAP NetWeaver Gateway today.

 

Efficiently meet IT challenges:

  • Architecture: Integrate teams, data, and processes across UIs and platforms
  • Development: Create apps faster to meet changing needs while working with your existing platforms and knowhow..
  • Technology: Help ensure robustness and security while minimizing disruptions.


Efficiently integrate Teams, Data, and Processes

  • Seamlessly integrate: teams, data, processes, and software in a way that is non-disruptive and fits your environment.
  • Reduce UI complexity, improve process efficiency and increase workforce productivity.
  • Use your existing software and infrastructure to minimize TCO and optimize ROI.

 

SAP NetWeaver Gateway makes your SAP data and processes consumable across a variety of platforms. Reduce app development complexity so you easily connect
everything using your existing infrastructure and skill set.  And, it enables you to create solutions without disrupting your existing business applications


NA/LatAm March 20th  12:00pm – 1:00pm EDT

     Customers (non s-users)                              Partners (s-users)
registerCustomer.png                         registerpartner.png

APJ March 26th  12:00pm – 1:00pm SGT

    Customers (non s-users)                               Partners (s-users)

registerCustomer.png                      registerpartner.png

 

EMEA March 27th  4:00pm – 5:00pm CET

   Customers (non s-users)                         Partners (s-users)

registerCustomer.png                       registerpartner.png


Let’s code CRUDQ and Function Import operations in OData service!

$
0
0

Introduction

 

In this blog I will explain creation of simple SAP NW GW OData service which will implement Create, Read, Update, Delete, Query and Function Import operations.


Just to make it very simple, I will just have single entity and entity set. Here I will perform these operations on Z table. In real scenarios, you will use BAPIs. RFCs to perform these operations.


I recommend to read below documents and SAP documentation for deep understanding.

How to Develop a Gateway Service using Code based Implementation by Andre Fischer

How to Develop Query Options for an OData Service Using Code-Based Implementationby Andre Fischer

How to Write an OData Channel Gateway Service. Part 2 - The Runtime Data Provider Class

SAP Help - SAP NetWeaver Gateway Foundation Developer Guide - SAP NetWeaver Gateway Foundation (SAP_GWFND) - SAP Library

Code Snippet - 3.2 Data Provider Class (DPC) - SAP NetWeaver Gateway Foundation (SAP_GWFND) - SAP Library


 

Scenario

 

We have User information table as ZUSERINFO containing below fields

gw1.jpg

Now let's create OData service which will insert, read, delete, update and query this table along with one custom operation (UsersByCountry) as function import.


From an ABAPer perspective, This is what meant by OData operations.

 

OData OperationHTTP MethodWhat it meant to an ABAPer
CreatePOSTInsert <table> from <workarea>
ReadGETSelect Single * From <table> into <workarea>
UpdatePUT/PATCHUpdate <table> set <workarea>
DeleteDELETEDelete from <table>
QueryGETSelect *  From <table> Into Table
Function ImportGET/POSTEverything covered by GET and POST. But only use if scenario does not fit into CRUDQ operations.


We can correlate Entity Set as Table Type, Internal table and Entity to work area, structure!


Entity SetTable Type or Internal Table
EntityStructure or Work Area



Procedure


Let’s go to transaction SEGW and create project as ZUSERINFO.

gw2.jpg

Now right click on Data Model and Import --> DDIC Structure option, it will display popup window. Provide DDIC structure name. In this case table name ZUSERINFO. It will propose field and key mapping as well as object name which will be your entity name.

gw3.jpg

We will ignore MANDT as key field and also overwrite object name. I want my field names in upper camel case format so I will change it accordingly.  Let’s call entity type as User. It will look as below. Press enter.

gw4.jpg

finally our entity type User will look as below.

gw5.jpg

Now let’s create Entity Set as UserCollection (or UserSet or Users). You can refer Creating High-Quality OData Services - SAP NetWeaver Gateway Foundation (SAP_GWFND) - SAP Library


I will go with UserCollection as my entity set name.


Right click folder name Entity Sets and click create. Provide entity set name as UserCollection and Entity Type name as User. It will display as below.

gw6.jpg

Now let’s generate runtime artifacts. Click on generate runtime objects button. It will display popup as below. Keep the default class names as-is and click on enter button.

gw7.jpg

On successful generation, you will see this kind of message log and generated artifacts. 4 classes will get generated. 2 for Data provider and 2 for Model provider.

gw8.jpg

Now register your service under service Maintenance folder. Click on Register button. Keep default values as-is and hit enter button.

gw9.jpg

On successful registration, click Maintain button. This will open service catalog window along with option to call Gateway Client. Click on Gateway Client button to test the service. (you can also call transaction /IWFND/GW_CLIENT to open SAP NW Gateway client)


Append $metatda to base service URL and press execute button. If everything is fine then you will HTTP Response as below. Metadata provides information such as Entity type, key property, properties and Entity Set name.

gw10.jpg

So far we just defined single entity type and entity set. Now it’s time to code CRUDQ and function import methods.

 

Coding


There is no specific order to implement these methods but it is always good to 1st implement query and read operation as for Create and Update, you will need request data which you will get if you already have query/read implemented.


1) Query Operation


First we will start implementing query operation. Before that, I will add one record in my ZUSERINFO table as

gw11.jpg

Now open Runtime artifacts folder and right click on Class ZCL_ZUSERINFO_DPC_EXT and select Go to ABAP Workbench option. Select edit mode and redefine method USERCOLLECTION_GET_ENTITYSET.

gw12.jpg

In the simplest form, this is what minimal coding will look like in GET_ENTITYSET method.

METHOD usercollection_get_entityset.

 

  DATA: lt_userinfo TYPETABLEOF zuserinfo,

        ls_userinfo LIKELINEOF lt_userinfo,

        ls_entity   LIKELINEOF et_entityset.

 

*Get data from ZUSERINFO table

  SELECT * FROM zuserinfo INTOTABLE lt_userinfo.

 

*Fill ET_ENTITYSET

  LOOPAT lt_userinfo INTO  ls_userinfo .

    ls_entity-userid    = ls_userinfo-userid.

    ls_entity-firstname = ls_userinfo-firstname.

    ls_entity-lastname  = ls_userinfo-lastname.

    ls_entity-email     = ls_userinfo-email.

    ls_entity-phone     = ls_userinfo-phone.

    ls_entity-country  = ls_userinfo-country.

    APPEND ls_entity TO et_entityset.

  ENDLOOP.

 

ENDMETHOD.

 

We are selecting all data from table ZUSERINFO and appending the result to exporting parameter ET_ENTITYSET.


Now you can go to GW client transaction and execute URI  /sap/opu/odata/sap/ZUSERINFO_SRV/UserCollection which will display one record which we already added into Z table.

gw13.jpg

Observe the method signature. put external breakpoint in method and execute query. You will find important information in method parameters in debugging mode.


Below table will provide brief explanation of method parameters, alternative approach to get the value of those method parameters. Last column specifies if we need to code to implement query operation.


Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_ENTITYSET


OData QueryMethod ParameterAlternative way to get the valueCoding required to implement Query Operation
UserCollection?$filter=UserID eq '123' and LastName eq 'Mahajan'IT_FILTER_SELECT_OPTIONS and IV_FILTER_STRINGDATA: my_filter_options TYPE /iwbep/t_mgw_select_option,
my_filter_string
TYPE string.
my_filter_options
= io_tech_request_context->get_filter( )->get_filter_select_options( ).
my_filter_string 
io_tech_request_context->get_filter( )->get_filter_string( ).
Yes
UserCollection?$select=FirstName,LastNameNo method parameter data: my_select_fields type /iwbep/t_mgw_tech_field_names.
my_select_fields
= io_tech_request_context->get_select( ).
No

UserCollection?$orderby=FirstName,LastName


OR


UserCollection?$orderby=FirstName desc,LastName desc
IT_ORDERdata: my_orderby_fields type /iwbep/t_mgw_tech_order.
my_orderby_fields
= io_tech_request_context->get_orderby( ).
Yes
UserCollection?search='test'IV_SEARCH_STRINGdata: my_search_string type string.
my_search_string
= io_tech_request_context->get_search_string( ).
Yes
UserCollection?$top=1IS_PAGING-TOP

data: my_top type string.
my_top
io_tech_request_context->get_top( ).

 

  data: my_skip type string.
my_skip
io_tech_request_context->get_skip( ).
Yes
In case if we had association and navigation between 2 entities IT_NAVIGATION_PATHDATA: my_nav_path type /iwbep/t_mgw_tech_navi.
my_nav_path
= io_tech_request_context->get_navigation_path( ).
Yes


 

2) Read Operation


Now let’s implement GET_ENTITY method. Go to method USERCOLLECTION_GET_ENTITY and redefine it. Below is the minimal code that we need to have in this method.


We need to read the key values passed from query URI and then fill the export parameter ER_ENTITY.

METHOD usercollection_get_entity.

 

DATA:  ls_key_tab   TYPE /iwbep/s_mgw_name_value_pair,

        lv_userid   TYPE zuserinfo-userid,

        ls_userinfo TYPE  zuserinfo.

 

*Get the key property values

READTABLE it_key_tab WITHKEY name = 'UserID'INTO ls_key_tab.

 

  lv_userid = ls_key_tab-value.

 

*Get the single record from ZUSERINFO and fill ER_ENTITY

SELECTSINGLE * FROM zuserinfo INTO ls_userinfo WHERE userid = lv_userid.

  IF sy-subrc = 0.

    er_entity-userid    = ls_userinfo-userid.

    er_entity-firstname = ls_userinfo-firstname.

    er_entity-lastname  = ls_userinfo-lastname.

    er_entity-email     = ls_userinfo-email.

    er_entity-phone     = ls_userinfo-phone.

    er_entity-country   = ls_userinfo-country.

  ENDIF.

 

ENDMETHOD.

 

Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_ENTITY

 

OData QueryMethod ParameterAlternative way to get the valueCoding required to implement Query Operation
UserCollection(UserID='Test') OR UserCollection('Test'IT_KEY_TABDATA: lt_keys TYPE /iwbep/t_mgw_tech_pairs.
lt_keys
= io_tech_request_context->get_keys( ).
Yes
In case if we had association and navigation between 2 entitiesIT_NAVIGATION_PATHDATA: my_nav_path type /iwbep/t_mgw_tech_navi.
my_nav_path
= io_tech_request_context->get_navigation_path( ).
Yes

UserCollection('Test')?$select=FirstName,LastName

NoDATA: my_select_fields TYPE /iwbep/t_mgw_tech_field_names.
my_select_fields
= io_tech_request_context->get_select( ).
No
UserCollection('Test')?$format=jsonNoNoNo

 


Also note that you cannot use system query options else you will get an error as System query options '$orderby,$skip,$top,$skiptoken,$inlinecount,' are not allowed in the requested URI


3) Create Operation


Now we will focus on create operation by redefining method USERCOLLECTION_CREATE_ENTITY. Below is the code that will perform POST operation.


Here we are reading the request data and then filling the exporting parameter ER_ENTITY.

METHOD usercollection_create_entity.

  DATA: ls_request_input_data TYPE zcl_zuserinfo_mpc=>ts_user,

        ls_userinfo TYPE zuserinfo.

 

* Read Request Data

  io_data_provider->read_entry_data(IMPORTING es_data = ls_request_input_data ).

 

* Fill workarea to be inserted

  ls_userinfo-userid   = ls_request_input_data-userid.

  ls_userinfo-firstname = ls_request_input_data-firstname.

  ls_userinfo-lastname = ls_request_input_data-lastname.

  ls_userinfo-email    = ls_request_input_data-email.

  ls_userinfo-phone    = ls_request_input_data-phone.

  ls_userinfo-country  = ls_request_input_data-country.

 

* Insert Data in table ZUSERINFO

  INSERT zuserinfo FROM ls_userinfo.

  IF sy-subrc = 0.

    er_entity = ls_request_input_data."Fill Exporting parameter ER_ENTITY

  ENDIF.

ENDMETHOD.

To test POST operation, 1st execute GET operation and then press Use as Request button which will copy the response to request window and then select operation POST and execute.


In case you execute GET operation i.e. GET_ENITITYSET and then try to perform POST operation then you will get below kind of error. Hence make sure that you execute GET to read single entity i.e. GET_ENTITY operation and then perform POST.

gw14.jpg

So correct steps are,

1) Execute GET to read single entity /sap/opu/odata/sap/ZUSERINFO_SRV/UserCollection('Test')

2) Click Use as Request button

3) Update your request properties.

4) Select HTTP method as POST

5) Query as /sap/opu/odata/sap/ZUSERINFO_SRV/UserCollection and execute

gw15.jpg


Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_ENTITY_C


OData QueryMethod ParameterCoding required to implement Query Operation
/sap/opu/odata/sap/ZUSERINFO_SRV/UserCollectionDATA: ls_request_input_data TYPE zcl_zuserinfo_mpc=>ts_user.
io_data_provider
->read_entry_data( IMPORTING es_data = ls_request_input_data ).
Yes


In case of Create operation, you cannot use system query options else you will get an error as

The Data Services Request contains SystemQueryOptions that are not allowed for this Request Type


This error message comes from method PROCESS_ENTITY_SET (/IWCOR/CL_DS_PROC_DISPATCHER). Just in case if you are curious and want to know

 

4) Update Operation


Now we will implement update operation by redefining method USERCOLLECTION_UPDATE_ENTITY. We need to put below code in this method.

METHOD usercollection_update_entity.

  DATA:  ls_request_input_data TYPE zcl_zuserinfo_mpc=>ts_user,

         ls_key_tab            TYPE /iwbep/s_mgw_name_value_pair,

         lv_userid             TYPE zuserinfo-userid,

         ls_userinfo           TYPE zuserinfo.

* Get key values

  READTABLE it_key_tab WITHKEY name = 'UserID'INTO ls_key_tab.

  lv_userid = ls_key_tab-value.

  IF lv_userid ISNOTINITIAL.

 

* Read request data

    io_data_provider->read_entry_data(IMPORTING es_data = ls_request_input_data ).

 

* Update fields of table ZUSERINFO

    UPDATE zuserinfo SET firstname = ls_request_input_data-firstname

                         lastname  = ls_request_input_data-lastname

                         email     = ls_request_input_data-email

                         phone     = ls_request_input_data-phone

                         country   = ls_request_input_data-country

                         WHERE userid  = lv_userid.

    IF sy-subrc = 0.

      er_entity = ls_request_input_data."Fill exporting parameter ER_ENTITY

    ENDIF.

  ENDIF.

ENDMETHOD.

Here also first we need to execute GET operation to read the entity and then copy the response to request using Use as Request button and execute PUT operation after editing required data. Successful HTTP response will look as below with status code as 204.

gw16.jpg

Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_ENTITY_U


OData QueryMethod ParameterAlternative way to get the valueCoding required to implement Query Operation
UserCollection('Test1')IT_KEY_TAB

DATA: lt_keys TYPE /iwbep/t_mgw_tech_pairs,

     ls_key TYPE /iwbep/s_mgw_tech_pair.

  lt_keys = io_tech_request_context->get_keys( ).
Yes
UserCollection('Test1')IO_DATA_PROVIDERio_data_provider->read_entry_data( IMPORTING es_data = ls_request_input_data ).Yes

 

5) Delete Operation


To implement Delete operation, you need to execute DELETE HTTP method for particular key. Below is the code for method USERCOLLECTION_DELETE_ENTITY.


Here we are reading key value of the record to be deleted and executing Delete statement.

METHOD usercollection_delete_entity.

  DATA:  ls_key_tab TYPE /iwbep/s_mgw_name_value_pair,

         lv_userid TYPE zuserinfo-userid.

* Read key values

  READ  TABLE it_key_tab INTO ls_key_tab WITHKEY name = 'UserID'.

  lv_userid = ls_key_tab-value.

  IF lv_userid ISNOTINITIAL.

* Delete record from table ZUSERINFO

    DELETEFROM zuserinfo WHERE userid = lv_userid.

  ENDIF.

ENDMETHOD.

On successful record deletion, you will see HTTP response code as 204.

gw17.jpg

Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_ENTITY_D

 

OData QueryMethod ParameterAlternative way to get the valueCoding required to implement Query Operation
UserCollection('Test1')IT_KEY_TAB

DATA: lt_keys TYPE /iwbep/t_mgw_tech_pairs,

     ls_key TYPE /iwbep/s_mgw_tech_pair.

  lt_keys = io_tech_request_context->get_keys( ).
Yes

 

6) Function Import 

 

As per SAP documentation, Function Imports - SAP NetWeaver Gateway Foundation (SAP_GWFND) - SAP Library

The Open Data Protocol (OData) includes standard CRUD (Create, Retrieve, Update, and Delete) operations that map to the HTTP methods POST, GET, PUT/MERGE, and DELETE.

In addition, OData supports further service operations (function imports) that can be invoked by the HTTP methods GET or POST for anything that cannot be mapped to the standard CRUD operations. You can implement such additional service operations in the Service Builder by creating function imports within your data model.

For example, you could create function imports for the following custom operations:

  • Confirm Work Item
  • Check Flight Availability

While it is simple to create new function imports to invoke custom operations, if the operation you want to use can be invoked using a standard CRUD operation, you should not create a function import. That is, you should only create function imports for custom operations that cannot be invoked using a standard operation.

 

In simple terms, if an operation cannot fit into CRUD scenario then you can perform it by function import.


Suppose our ZUSERINFO table looks like below,

gw18.jpg

And we want to get users by specific country then we can implement function import. Let’s call our function import as UsersByCountry!

Right click on Data model and create function import. Provide proper name. Again refer Creating High-Quality OData Services - SAP NetWeaver Gateway Foundation (SAP_GWFND) - SAP Library

gw19.jpg

Provide required details such as mentioned below. Remember here we want to return collection of users and hence we selected Return cardinality as 0..n with return entity set and HTTP method type as GET.

gw20.jpg

Now click on Function Import parameters and create import parameters as shown below. In this case we just want to pass value of country and hence we will have one parameter as Country.

gw21.jpg

Finally save project, check project consistency and generate runtime objects. To check if everything is fine, in GW client execute service metadata URL as /sap/opu/odata/sap/ZUSERINFO_SRV/$metadata which should show you function import definition in metadata as below,

gw22.jpg

Now we will implement function import operation. Go to DPC_EXT class and redefine method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~EXECUTE_ACTION.

Put below code to implement function import.

METHOD /iwbep/if_mgw_appl_srv_runtime~execute_action.

  DATA: ls_parameter  TYPE /iwbep/s_mgw_name_value_pair,

        lv_country    TYPE string,

        lt_userinfo   TYPETABLEOF zuserinfo,

        ls_userinfo   TYPE zuserinfo,

        ls_entity     TYPE  zcl_zuserinfo_mpc=>ts_user,

        lt_entityset  TYPE zcl_zuserinfo_mpc=>tt_user.

 

 

  IF iv_action_name = 'UsersByCountry'." Check what action is being requested

    IF it_parameter ISNOTINITIAL.

* Read Function import parameter value

      READTABLE it_parameter INTO ls_parameter WITHKEY name = 'Country'.

      IF sy-subrc = 0.

        lv_country = ls_parameter-value.

      ENDIF.

 

      IF lv_country ISNOTINITIAL.

        SELECT  * FROM zuserinfo INTOTABLE lt_userinfo WHEREcountry = lv_country.

        LOOPAT lt_userinfo INTO  ls_userinfo .

          ls_entity-userid   = ls_userinfo-userid.

          ls_entity-firstname = ls_userinfo-firstname.

          ls_entity-lastname = ls_userinfo-lastname.

          ls_entity-email    = ls_userinfo-email.

          ls_entity-phone    = ls_userinfo-phone.

          ls_entity-country  = ls_userinfo-country.

          APPEND ls_entity TO lt_entityset.

        ENDLOOP.

* Call methos copy_data_to_ref and export entity set data

        copy_data_to_ref(EXPORTING is_data = lt_entityset

                CHANGING cr_data = er_data ).

 

      ENDIF.

    ENDIF.

  ENDIF.

 

ENDMETHOD.

 

To test function import we need to query as /sap/opu/odata/sap/ZUSERINFO_SRV/UsersByCountry?Country='US'


If there are multiple parameters then it will be separated by comma.

gw23.jpg

Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_FUNC_IMPORT


OData QueryMethod ParameterAlternative way to get the valueCoding required to implement Query Operation
/sap/opu/odata/sap/ZUSERINFO_SRV/UsersByCountry?Country='US'IT_PARAMETERDATA: my_parameter TYPE  /iwbep/t_mgw_name_value_pair.
my_parameter
= io_tech_request_context->get_parameters( ).
Yes

 

 

Closing Remarks

 

This is very simple example of an OData service. In real case scenarios, you will have multiple entities, relationship, association and navigation between them but when it comes to coding in DPC_EXT class methods, you will find above explanation of each method, parameters and alternative way to get the parameter values useful.

 

I hope you enjoyed reading this blog and now ready to develop your OData service! I request you toput comments/suggestions. Please feel free if you have any different thought to improve any part of this blog as well.

 

Happy Learning & Coding

How to consume an OData Service of SAP NetWeaver Gateway with Apache Olingo

$
0
0

How to consume an OData Service of SAP NetWeaver Gateway with Apache Olingo


This article shows how to consume (Read) an OData Service with support of the Apache Olingolibrary.


As OData Service a gateway demo service is used which defines a data model containingBusinessPartners and their related Products they sell. For this sample we assume an use case that a client (e.g. UI) is interested in all offered Products and in addition the related BusinessPartner which supplies the Product.


To implement and demonstrate the described use case following steps have to be proceeded:


  • Fulfil prerequisites to access the gateway OData demo service
  • Read a single Product and Read all available Products
  • Navigation from a Product to the related BusinessPartner
  • Inclusion of information of related Entries to reduce requests
  • Selection of wanted information from Entries to reduce transfered data


Prerequisites

The gateway demo service is named ZGWSAMPLE_SRV and the functionality the service provides is described here. To get access to the gateway demo service it is necessary to sign up as described.


Read

Apache Olingo provides client functionality in form of create Requests (serialization) and interpret Responses (deserialization) based on the OData format. It does not provide functionality for sending and receiving requests so an application is free to decide whatever HTTP client library it wants to use. The methods to access provided serialization and deserialization functionality are all declared at the EntityProvider class. For basic consumption (Read) of an OData Service following methods are necessary:


  • EntityProvider.readMetadata(...) to read the metadata of the service.
  • EntityProvider.readEntry(...) to read an single entry.
  • EntityProvider.readFeed(...) to read a collection of entities.


Read Prerequisites: EDM/$metadata


Because Apache Olingo requires the metadata for serialization and deserialization of an entity the first step is to read the whole Entity Data Model (EDM) of an OData Service.


public Edm readEdm(String serviceUrl) throws IOException, ODataException {  InputStream content = execute(serviceUrl + "/" + METADATA, APPLICATION_XML, HTTP_METHOD_GET);  return EntityProvider.readMetadata(content, false);
}

To read the Entity Data Model (EDM) a HTTP GET on the corresponding $metadata URI of the OData Service via the execute(...) method. The resulting content is passed into theEntityProvider.readMetadata(InputStream content, boolean validate) method which de-serialize the EDMX into an EDM object. This EDM object than can be used for necessary deserialization in combination of read operations.


Read Entity: Product


To read a single Product of the service a single request to the ProductsCollection URI with set ID is done.

 

public ODataEntry readEntry(Edm edm, String serviceUri, String contentType, String entitySetName, String keyValue)  throws IOException, ODataException {
// working with the default entity container
EdmEntityContainer entityContainer = edm.getDefaultEntityContainer();
// create absolute uri based on service uri, entity set name and key property value
String absolutUri = createUri(serviceUri, entitySetName, keyValue);
InputStream content = execute(absolutUri, contentType, HTTP_METHOD_GET);
return EntityProvider.readEntry(contentType,    entityContainer.getEntitySet(entitySetName),    content,    EntityProviderReadProperties.init().build());  }

The execute(...) method executes the request against the absolute URI and returns the response content as InputStream which then is deserialized by the EntityProvider.readEntry(...) into anODataEntry object. This contains all properties (data) of the entry in form of a Map, additional entry metadata as EntryMetadata object (which contains etag, id, association uris and uri information), the ExpandSelectTreeNode, information whether the entry contains inline entries and if the entry is a media resource additional the MediaMetadata.


Read Entities: ProductCollection


To read all Products of the service a single request to the ProductsCollection URI is done.


public ODataFeed readFeed(Edm edm, String serviceUri, String contentType, String entitySetName)    throws IOException, ODataException {  EdmEntityContainer entityContainer = edm.getDefaultEntityContainer();  String absolutUri = createUri(serviceUri, entitySetName, null);  InputStream content = (InputStream) connect(absolutUri, contentType, HTTP_METHOD_GET).getContent();  return EntityProvider.readFeed(contentType,      entityContainer.getEntitySet(entitySetName),      content,      EntityProviderReadProperties.init().build());
}

The execute(...) method executes the request against the absolute URI and returns the response content as InputStream which then is deserialized by the EntitProvider.readFeed(...) into anODataFeed object. This contains all entities provided by the OData Service as ODataEntry in a list as well as FeedMetadata like inline count and next link.

All used URIs


Navigate

The demo service defines an association between Products and their releated BusinessPartners as navigation property at a Product with the name Supplier. By following that association theBusinessPartner can be retrieved. This can be done by calling the absolute URI to a Supplier of a single Product which can be get by using the getAssociationUris(...) method of theEntryMetadata object. In this example the metadata object method is called with parameterSupplier which then returns with a list which contains the absolute URI (e.g. https://sapes1.sapdevcenter.com/sap/opu/odata/sap/ZGWSAMPLE_SRV/ProductCollection('HT-1000')/Supplier) which can be called to get the Supplier for the Product.

For this example we prefer to already include the Supplier information for a Product into the response of our request. Therefore a read with expand system query option is the way to go (in next section).

All used URIs


Read more with Expand

To read an Entry or Feed which already includes properties of a related Entry (or Entries) the$expand system query option can be used. The $expand clause is a list off all associations to be retrieved within this request. For the example the $expand parameter is set to the navigation property Supplier to be retrieved. This results in the following relative URI:"./ProductCollection('HT-1000')/?$expand=Supplier".


The client has only to append the $expand for this case and can then again parse the result viaEntityProvider.readEntry(...). The difference now is that containsInlineEntry() is true and the Supplier properties are available as ODataEntry within the properties (i.e. Map) of the Product. To visualize the Map looks like:

 

Product (as ODataEntry)
\- *additional information like EntryMetadata*
\- *all simple properties*
\- Supplier (as ODataEntry)    \- *additional information like EntryMetadata*    \- *all simple properties*

The above shown readEntry(...) method could be used with minor adaption of URI creation, which now has to include the name of the expanded navigation property.

 

String absolutUri = createUri(serviceUri, entitySetName, keyValue, expand);

All used URIs

Read more with Expand on a Feed


As mentioned in the section above the $expand can also be used to read a Feed so that then as example each Product already includes the related Supplier. Also EntityProvider.readFeed(...)can be used for deserialization and the only adaption in compare to normal read Feed use case is to append the $expand system query option. For the sample use case the relative URI is"../ProductCollection/?$expand=Supplier".

All used URIs


Read less with Select

Each response usually contains all properties for an entry but this is not necessary for each client use case. Hence, for a use case in that a client is only interested in some properties it is possible to define the system query option $select to specify which properties of an Entry should be sent in the response payload. As example we only want the Name of each Product and the CompanyName of the related Supplier. Then we can use the $expand to include the Supplier in the response and define the $select system query option with Name,Supplier/CompanyName which results in the relative URI "../ProductCollection/?$select=Name,Supplier/CompanyName&$expand=Supplier".


Again the EntityProvider.readFeed(...) method is used for deserialization and the only adaption in comparison to the read Feed with expand use case is appending the $select system query option in creation of the URI.

 

String absolutUri = createUri(serviceUri, entitySetName, keyValue, expand, select);

All used URIs


Conclusion

In the sections above it was shown that with the support of Apache Olingo it is relatively easy for a client to consume an OData Service. While the library takes care of serialization and deserialization of the OData formatted entities the client can focus on processing the data.

Runnable sample client

A sample client exists for a quick Hands-On covering the here shown read use cases and in addition containing the boiler plate code which is necessary for the URL connection handling (e.g. Proxy/Authentication support).


To run this sample follow these steps:


  • Prerequisite: An installed JVM (Version 1.6 or above) and Maven (Version 3 or above).
  • Download it here.
  • Extract it into some folder
  • Configure proxy and/or authentication in client.properties in folder src/main/resources(with credentials provided via signing up)
  • Execute mvn compile exec:java to run Maven which compiles and executes the sample project.

Step by step guides for OAuth 2.0 with NetWeaver Gateway

OData 4.0 is now an OASIS Standard

$
0
0

A new, streamlined and enhanced version of the Open Data Protocol has been approved as an OASIS Standard; see the press release from OASIS. After eighteen months of intense work, several public reviews, and careful consideration of all the feedback received, a joint team from Axway Software, Blackberry, CA Technologies, Citrix Systems, IBM, Microsoft, Progress Software, Red Hat, SAP AG, SDL, and many others now proudly presents OData Version 4.0. The specification consists of four documents:

 

OData fosters easy access to business data and interoperability between different product lines. OData Version 2.0 is supported by many SAP products; to name just a few:

  • SAP NetWeaver Gateway
  • SAP HANA XS
  • SAP Mobile Platform
  • SAP Sybase SQL Anywhere
  • SAP Jam
  • SuccessFactors Employee Central
  • SAP Crystal Reports

 

The new OData Version 4.0 has been shaped by the feedback we received from many product teams using OData at SAP, and our tools and infrastructure teams have closely accompanied the standardization process, providing a valuable reality check for the specification team in the OASIS Technical Committee. One of these teams is driving the Apache Olingo incubator project, providing OData server and client libraries for Java and JavaScript. Initiated by SAP, this open-source project has recently been joined by Microsoft Open Technologies and is now implementing OData 4.0 for Java servers and clients as well as JavaScript clients.

 

I'm looking forward to many SAP products speaking OData 4.0 in addition to the prior version 2.0, allowing to build even more powerful applications.

 

An overview of What's New in OData Version 4.0 has been published by the specification team, and I will write about the features that are most important for SAP here on SCN. A short overview is also provided in the blog posts of my specification co-author Mike Pizzo and my TC co-chair Ram Jeyaraman.

 

The standardization of OData is an ongoing effort, and the specification team is now focussing on extension specifications, the most important being the OData Extension for Data Aggregation Version 4.0. It recently has reached Committee Specification status, meaning it is ready for implementation.

 

Please have a look at the specifications and comment here on the OData 4.0 features you are most eager to see implemented!

Connecting Google Docs to SAP NetWeaver Gateway

$
0
0

I'll gladly admit: I was really excited when the announcement came last week that Google Docs and Sheets would be open to third-party add-ons developed in Google Apps Script.  It opens the door to all sorts of interesting application integration capabilities, and enhances them with the collaboration tools and ubiquity of Google Drive.

 

The software developer in me immediately thought "I'll bet I can plug that into Gateway!"  The power of SAP NetWeaver Gateway to take anything in a Business Suite system and expose it for consumption through OData REST services means that a wide variety of consumers can make use of this data - and Docs and Sheets are no exception.  There's a built-in API for communicating with other internet services, powerful XML parsing, and even support for an html-based UI paradigm.

 

So here's how I created a simple add-on to read and display data from a Gateway service in a Google Sheets document.  When it's all finished and pulling data, it should look something like this (including the sample data I pulled from my service):

final look apps script project.PNG

 

Prerequisites:

  • A Google account, so you can create documents on your Drive.
  • A Gateway service that returns some sort of useful entity data.  I created a simple service that just spits out contrived data for contracts that I stored in a z-table on the SAP side - but this could be any service you want.
  • Basic knowledge of javascript.  Really not much expertise needed - it doesn't take much code to hook up this minimalist tool.

 

Set up the Apps Script Project:

  • Create a spreadsheet anywhere in your Drive:
    • Sign in at docs.google.com
    • Click the "Create" button on the left side
    • Choose "Spreadsheet"
  • Create an Apps Script project:
    • Open the new spreadsheet
    • Click the "Tools" menu
    • Choose "Script Editor..."
    • On the wizard that appears, choose "Blank Project"

You should see an untitled project with one source code file (Code.gs) and an empty myFunction() declaration like this:

beginning apps script project.PNG

You can name the project anything you like.  When the project is complete and running in your spreadsheet, the name of the project will be the first layer of the add-on menu to navigate to this functionality. 


Build Your Code:

We can code up this simple example in about 150 lines of javascript and html.  I'll split the coding into 3 blocks so as to explain what is going on.

 

First, take out all the existing code in the Code.gs file.  Replace it with the below code:


function onInstall() { 
   onOpen(); 

  
function onOpen() { 
   SpreadsheetApp.getUi().createAddonMenu() 
     .addItem('Retrieve SAP Data', 'showSidebar') 
     .addToUi(); 

  
function showSidebar() { 
   var ui = HtmlService.createHtmlOutputFromFile('Sidebar') 
              .setTitle('Data Viewer'); 
  
   SpreadsheetApp.getUi().showSidebar(ui); 
  


This code is adding the menu under the "Add-ons" menu that appears on the spreadsheet.  It enables you to have the menu structure you wish for your application.  In the next step we'll create the html file necessary to render a sidebar menu.


Why is there an onInstall() and an onOpen(), and onInstall() just calls onOpen()?  It has to do with how installations work in Apps Script.  When you install an add-on, your document is already open and thus does not trigger the onOpen() event.  The onOpen() method is added to onInstall() so that when the script is installed, it also performs the menu setup and other tasks that would normally occur when the document opens.


The addItem() call is registering the function showSidebar() to be triggered when you click on "Retrieve SAP Data".  This is how we're going to open the sidebar menu that we create.


Here's what mine looks like:

menu structure.png

Next, create an html file in your project.  In the menus follow File...New...Html file, and name your html file "Sidebar".  Put the following code in:


<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css"> 
<!-- The CSS package above applies Google styling to buttons and other elements. --> 
  
<div class="sidebar branding-below"> 
   <form> 
   <div class="block" id="credentials">SAP Connection Information<br> 
     <input type="text" id="serviceaddress" placeholder="Service Address"><br> 
     <input type="text" id="userid" placeholder="User ID"><br> 
     <input type="password" id="password" placeholder="Password"> 
   </div> 
   <div class="block" id="button-bar"> 
     <button class="blue" id="read-data">Read Data</button> 
   </div> 
  </form> 
</div> 
  
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"> 
</script> 
<script> 
  
   $(function() { 
     $('#read-data').click(readData); 
   }); 
  
   function readData() { 
  
     var token = $('#userid').val() + ':' + $('#password').val(); 
     var serviceaddress = $('#serviceaddress').val(); 
  
     //Call out to the Code.gs script function readContracts 
     google.script.run 
       .readData(token, serviceaddress); 
  
  } 
  
</script> 


Here we've defined a simple user interface that has four components: an input that accepts a URI for the Gateway service you want to read, an input that accepts an SAP user name, an input that accepts an SAP password, and a button that triggers the read activity.  We've also used the included jQuery to register an event on the button so that when you click "Read Data" you'll call out to the appropriate function to read the data you've chosen.  The nice thing about the html files used for the sidebar is that they can be customized with javascript/css/html like any other part of the web, so they can be very flexible and built to suit a lot of different needs.


Next, go back to the Code.gs file, and insert the below code after the showSidebar() function.


function readData(authinfo, serviceaddress) { 
  
   //Clean up anything currently on the spreadsheet 
   SpreadsheetApp.getActiveSheet().clear(); 
  
   try { 
     var options = { 
       headers: { 
         'Authorization': 'Basic ' + Utilities.base64Encode(authinfo) 
       }, 
     }; 
  
     //UrlFetchApp is a powerful built-in library from Google 
     var response = UrlFetchApp.fetch(serviceaddress, options); 
  
     //Various XML parsing. 
     var xml = response.getContentText(); 
     var document = XmlService.parse(xml); 
     var root = document.getRootElement(); 
     var atom = XmlService.getNamespace('http://www.w3.org/2005/Atom'); 
     var entries = document.getRootElement().getChildren('entry', atom); 
  
     //This loop handles the writing of the response data 
     //to the spreadsheet. 
     var row = 1; 
     for (var i = 0; i < entries.length; i++) { 
       //Navigate the xml response document to get properties/values
       var content = entries[i].getChildren('content', atom); 
       var properties = content[0].getChildren(); 
       var values = properties[0].getChildren(); 
    
       //First pass through the outer loop we will use to also write 
       //the header row, using the properties as column headers. 
       if (i == 0) { 
         var headercolumn = 0; 
         for (var j = 0; j < values.length; j++) { 
           headercolumn++; 
           SpreadsheetApp 
             .getActiveSheet() 
             .getRange(1, headercolumn) 
             .setValue(values[j].getName()); 
         } 
       } 
    
       //Now write the values of the properties 
       row++; 
       var column = 1; 
       for (var j = 0; j < values.length; j++) { 
         SpreadsheetApp 
           .getActiveSheet() 
           .getRange(row, column) 
           .setValue(values[j].getText()); 
    
         column++; 
       }
     } 
   } 
   catch(err) { 
     //Write any retrieve or parse errors into A1 of the main sheet 
     SpreadsheetApp 
       .getActiveSheet() 
       .getRange('A1') 
       .setValue(err.message); 
   }   


This function is the meat and potatoes of this demo.  We're handling basic authorization, the http request and retrieve of service data, and parsing/writing that information into the document.  If I was writing this code for a professional application you can bet I'd be following a few more Code Complete conventions.


(You can see that in this demo we use basic authentication: taking the user ID and password from the sidebar, using the Google provided Utilities.base64Encode(), and passing that into the header of the request. To turbocharge your security/single sign-on, Google also provides some built-in OAuth handling you can check out in the documentation.)


UrlFetchApp is another powerful built-in tool in Apps Script.  This lets you handle the http/https requests and get the responses.  In this case to get at the xml that Gateway is handing back to us, we use the HTTPResponse method getContentText().  It's not built into a full document model yet, so we use yet another built-in tool to create and parse the xml: XmlService.  Any of the response, document, entry, or properties variables in this code are based on parsing that xml.

 

The <entry> node holds a single data record of the response, which is why we base the outer for loop on the number of <entry> nodes.  On the first pass through the loop we also examine the properties of the data, so that we can write out a header line for the data.  After that, it's just a matter of popping the data into cells of the spreadsheet.

 

That's basically it!  We now have a small script that can pull out data from a Gateway service.  This is very very basic stuff - if you want to do anything interesting, you'll obviously have a lot more work in front of you.  Nevertheless, I hope this is food for thought!

There is a Gateway for that ...

$
0
0

For decades, SAP customers and the partners in the ecosystem have been building solutions that access SAP data. For a long time, such access was only possible via a number of proprietary technologies offered by SAP such as RFC, BAPI, IDocs and even Enterprise Services.

 

With the recent popularity of REST (Representational state transfer) against SOA (Service-oriented architecture) which is typically based on the SOAP (Simple Object Access Protocol), SAP is embracing OData (Open Data Protocol) as the protocol to provide standards based access to SAP data.

 

Concept Gateway

Concept Gateway is the vision for a harmonized integration layer by which all SAP solutions can be accessed via OData. To do that individual solutions provide design-time tools for exposing their data as OData services based on their native platforms. The concept also suggest that based on OData services coming from various SAP solutions, a consistent user-experience can be provided by leveraging standards like HTML5 and CSS3 – e.g. SAP UI5.

 

Following diagram depicts “Concept Gateway” inside SAP’s ever increasing solutions portfolio.

CGW.png

SAP NetWeaver Gateway

Built on the traditional ABAP technology, SAP NetWeaver Gateway is a technology solution that provides design-time and runtime features to expose SAP Business Suite data as OData services (i.e. RESTful APIs).

 

SAP NetWeaver Gateway became generally available in October 2011 and by the end of 2013, in about two years it was adopted by more than 7000 customers, productively.

 

NWGW.png

 

With SAP NetWeaver Gateway, customers can build OData services based on existing SAP APIs such as RFC, BAPI, BOR, BOL, MDX, SAP HANA and others. Furthermore, SAP NetWeaver Gateway comes with design-time tools to allow modeling of OData services as well as provisioning of such services from scratch by custom coding, in ABAP.

 

While SAP NetWeaver Gateway is great for exposing SAP data from an ABAP based SAP system, it does not provide tools for exposing data from non-ABAP based SAP systems.

 

Integration Gateway

Over the last 40 years, SAP’s solutions portfolio has grown from traditional ERP to cover 10+ LoBs, 20+ industries in 100+ countries (i.e. localizations) through technology innovations and acquisitions. As a result, a harmonized design-time (as well as user experience) and a harmonized Integration Layer across the portfolio have become essential to bring the benefits that SAP NetWeaver Gateway offers SAP Business Suite customers.

 

Integration Gateway is a technology component that provides design-time tools and the associated run-time for modeling, composing and provisioning OData services based on one or more APIs from various SAP and non-SAP data sources. Among the data sources supported today are, SOAP (Simple Object Access Protocol), JPA (Java Persistence API) and JDBC (Java Database Connectivity) to access non-SAP data sources as well as OData Channel (ODC) for accessing OData services provisioned via SAP NetWeaver Gateway.

 

IGW.png

 

Integration Gateway has been first delivered inside SAP Mobile Platform 3.0 as an on-premise solution. In this version, Integration Gateway has been fully implemented in Java and it runs on SAP Lean Java Server, a lightweight OSGi (Open Services Gateway) based application server.

 

In the future, Integration Gateway will be included in other on-premise or cloud based SAP solutions in their native platforms. However, at this time there are no plans to deliver it as a standalone solution.

 

Integration Gateway and SAP NetWeaver Gateway – Two sides of a coin

SAP NetWeaver Gateway focuses on exposing SAP data from an ABAP based SAP solution as OData services. Hence, it has design-time tools that natively support creating OData services, based on existing SAP APIs (RFCs, BAPIs, etc.) as well as from scratch.

 

Integration Gateway however, takes SAP one step closer to realizing the vision of “Concept Gateway” by bringing OData provisioning beyond SAP Business Suite by supporting several integration protocols and technologies that are well accepted in the industry. Furthermore, when it comes to accessing an SAP Business Suite backed (ABAP based), it relies on the OData services provisioned by SAP NetWeaver Gateway as it supports the ODC (OData Channel) protocol.

 

NGWvsIGW.png

 

NGWvsIGWchart.png

 

Answers to frequently asked questions

 

Q: I need to build an app that will access both SAP and non-SAP data (legacy, solutions from other vendors). Which Gateway do I need?

A: You will need both SAP NetWeaver Gateway and Integration Gateway.

Q: I am building a mobile app and I don’t need to access SAP backend. Do I need SAP NetWeaver Gateway?

A: No. If you don’t need to access SAP Business Suite backend, you may only need Integration Gateway.

Q: Where can I download Integration Gateway?

A: Integration Gateway is not available as a standalone solution. Currently, it only comes with SAP Mobile Platform 3.0.

Q: Where can I download SAP NetWeaver Gateway?

A: SAP NetWeaver Gateway is included in SAP NetWeaver 7.40. For earlier versions (starting from SAP NetWeaver 7.0) you will need to download it as an Add-on from SAP Service Marketplace – http://service.sap.com/swdc (SAP Service Marketplace username password required).

 

 

Best regards,

Mustafa.

Consuming an External RESTful Web Service with ABAP in Gateway

$
0
0

Look, you don't need to tell me.  I already know the truth, deep in my bones: ABAP is not the language the cool kids use.  Not even remotely on their radar.  They've got their Scalas, and their Rusts, and all 30 billion javascript frameworks to build hot startups with.  You can't even play with ABAP unless you work for a place that runs SAP or you're willing to download and install the massive (50 GB!) ABAP trial version

 

But when you look under the covers at the system functionality that ABAP exposes in SAP systems, it becomes apparent that the frameworks, libraries, and system tools that you have at your command can be crafted into an engine to power a phenomenal array of projects.  Just this morning I put together something that - while admittedly not incredibly useful all by itself - shows some of what you can accomplish if you have some familiarity with the tools SAP gives you in ABAP and Gateway. 

 

Let me show you.  It's not a ridiculously complex build, and it's just a slice of what you could do. 

 

At a high level what I've done is find an external RESTful web service, write some ABAP to consume it from the SAP side, and expose that data back out through Gateway.  It's a little bit contrived, since you could easily call this service without Gateway mediating the connection...but I think there are occasional valid reasons to mediate the service through Gateway.  You might have an account with the external service and need to manage your calls to it, or you might want to join the service data with other things from Business Suite services and make it all available in one entity type.  Or you're like me, and you just want to see if it could be done. 

 

I created a developer account with world weather online, so that I could use its API for free.  This lets you use a simple call to get a set of information on weather for a particular location, and in my case I use it to get the day's forecast with a given zip code.  If you sign up, you can use their neat API explorer to test out different ways to use the service. 

 

If I call the main weather service with my home zip code, I get the following structure back (some unnecessary stuff has been trimmed):

<?xml version="1.0" encoding="UTF-8"?>
<data>
   
<request>
       
<type>Zipcode</type>
       
<query>55426</query>
   
</request>
   
<weather>
       
<date>2014-03-27</date>
       
<tempMaxC>5</tempMaxC>
       
<tempMaxF>40</tempMaxF>
       
<tempMinC>-6</tempMinC>
       
<tempMinF>22</tempMinF>
       
<windspeedMiles>15</windspeedMiles>
       
<windspeedKmph>24</windspeedKmph>
       
<winddirection>ESE</winddirection>
       
<winddir16Point>ESE</winddir16Point>
       
<winddirDegree>123</winddirDegree>
        <weatherDesc>
            <![CDATA[Light rain]]>
       
</weatherDesc>
       
<precipMM>9.6</precipMM>
   
</weather>
</data>


Knowing the structure of what comes back to me, I can build some simple ABAP to do the same thing.  I set up a dictionary z-structure to hold the bits of data that I want to use:

weather structure.PNG


I then set up a function module to do pull data from the service and put it into that structure:

 

 

FUNCTION zweather_read_zip.
*"---------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     VALUE(IM_ZIPCODE) TYPE  AD_PSTCD1
*"  TABLES
*"      ET_WEATHER STRUCTURE  ZWEATHER
*"---------------------------------------------------------------

  DATA: lo_http_client TYPE REF TO if_http_client,
        lv_service TYPE string,
        lv_result TYPE string,
        lo_ixml TYPE REF TO if_ixml,
        lo_streamfactory TYPE REF TO if_ixml_stream_factory,
        lo_istream TYPE REF TO if_ixml_istream,
        lo_document TYPE REF TO if_ixml_document,
        lo_parser TYPE REF TO if_ixml_parser,
        lo_weather_element TYPE REF TO if_ixml_element,
        lo_weather_nodes TYPE REF TO if_ixml_node_list,
        lo_curr_node TYPE REF TO if_ixml_node,
        lv_value TYPE string,
        lv_node_length TYPE i,
        lv_node_index TYPE i,
        ls_weather TYPE zweather,
        lv_node_name TYPE string,
        lv_node_value TYPE string.

  lv_service = 'http://api.worldweatheronline.com/free/v1/weather.ashx'.

  lv_service =
lv_service && '?q=' && im_zipcode && '&format=xml'.

  lv_service = lv_service && '&key=[use your own!]'.

  cl_http_client=>create_by_url(
    EXPORTING
      url                = lv_service
    IMPORTING
      client             = lo_http_client
    EXCEPTIONS
      argument_not_found = 1
      plugin_not_active  = 2
      internal_error     = 3
      OTHERS             = 4 ).

  lo_http_client->send(
    EXCEPTIONS
      http_communication_failure = 1
      http_invalid_state         = 2 ).

  lo_http_client->receive(
    EXCEPTIONS
      http_communication_failure = 1
      http_invalid_state         = 2
      http_processing_failed     = 3 ).

  "Prepare XML structure
  CLEAR lv_result .
  lv_result = lo_http_client->response->get_cdata( ).
  lo_ixml = cl_ixml=>create( ).
  lo_streamfactory = lo_ixml->create_stream_factory( ).
  lo_istream = lo_streamfactory->create_istream_string(
                                   lv_result ).
  lo_document = lo_ixml->create_document( ).
  lo_parser = lo_ixml->create_parser(
                         stream_factory = lo_streamfactory
                         istream        = lo_istream
                         document       = lo_document ).

  "This actually makes the XML document navigable
  lo_parser->parse( ).

  "Navigate XML to nodes we want to process
  lo_weather_element = lo_document->find_from_name_ns(
'weather' ).
  lo_weather_nodes = lo_weather_element->get_children( ).

  "Move through the nodes and assign appropriate values to export
  lv_node_length = lo_weather_nodes->get_length( ).
  lv_node_index = 0.
  CLEAR ls_weather.
  WHILE lv_node_index < lv_node_length.
    lo_curr_node = lo_weather_nodes->get_item( lv_node_index ).
    lv_node_name = lo_curr_node->get_name( ).
    lv_node_value = lo_curr_node->get_value( ).

    CASE lv_node_name.
      WHEN 'date'.
        REPLACE ALL OCCURRENCES OF '-' IN lv_node_value WITH ''.
        ls_weather-forecast_date = lv_node_value.
      WHEN 'tempMaxF'.
        ls_weather-high_temp_f = lv_node_value.
      WHEN 'tempMinF'.
        ls_weather-low_temp_f = lv_node_value.
      WHEN 'windspeedMiles'.
        ls_weather-wind_speed = lv_node_value.
      WHEN 'winddir16Point'.
        ls_weather-wind_direction = lv_node_value.
      WHEN 'weatherDesc'.
        ls_weather-description = lv_node_value.
      WHEN 'precipMM'.
        ls_weather-precipitation = lv_node_value.
    ENDCASE.

    ADD 1 TO lv_node_index.
  ENDWHILE.

  APPEND ls_weather TO et_weather.

ENDFUNCTION.


 

I sprinkled some comments in the code to help, but I use the cl_http_client class to do the call to the service (and it can be set up and done in just 3 method calls), and then use a few of the xml library classes to parse the result and put it into the structure.  You can see here that though I've only made the zip code dynamic in the call, you could actually be pretty dynamic in choosing services to leverage. 

 

Why did I use a function module?  It's actuallyprettyeasy to use a function module as a basis for building services in SEGW on your Gateway system, so it can be convenient to wrap custom functionality into a function module and then just import definitions.  That's what I did to set up the entity and entity set for this simple service: 

weather demo segw setup.PNG

 

Note especially that the GetEntity method is mapped with zip code as the incoming parameter:

weather demo get entity.PNG


After this, when I activated the service, it's as simple as calling the URI with a parameter of some zip code that I want to see :


weather service result.PNG


Like I mentioned before, by itself this isn't much use.  But combine this with some other information and you start to see what you can really pull together and expose through Gateway.  It's pretty awesome to think that anything you could pull from a REST service on the web can also be a resource for your application. 


Step by Step development for CREATE_DEEP_ENTITY operation

$
0
0

This blog I will explain creation of SAP NW GW OData service which will implement  Create Deep Entity operation.


SAP documentation for deep understanding.


Deep Insert - SAP NetWeaver Gateway - SAP Library


Create Custom RFC  given below Structures.


Structure-1 - Header

Structure-2 - ItemO

Structure-3 - ItemT


1-rfc-sig.PNG21-st-head.PNG2-str-head.PNG22-st-itmt.PNG


Create Project in SEGW

 

Create three entity types and Entity Sets


Entity Type-1- Header    

Entity Type-2- ItemO

Entity Type-3- ItemT


Entity Set-1- HeaderSet

Entity Set-2- ItemOSet

Entity Set-3- ItemTSet



Entity Type - Header

segw-1.PNG

Entity Type - ItemO

segw-1-itemo.PNG

Entity Type - ItemT

segw-2-itemt.PNG

Entity Sets -  HeaderSet,ItemOSet,ItemTSet

segw-eneitysets.PNG



Create Associations given below


Association-1 -  Header_ItemO (Without key fields mapping)

Association-2 -  Header_ItemT (Without key fields mapping)


asso-1-2.PNG


Create Navigation given below


Navigation-1 -  HeadItemO

Navigation-2 -  HeadItemT


novg-1-2-.PNG


Now let’s generate runtime artifacts. Click on generate runtime objects button. It will display

popup . Keep the default class names as-is and click on enter button.

 

Once generation is successful, you will get 4 classes. 2 for Data provider and 2 for Model provider.

serv-reg.PNG

 

Once registration done successfully .Goto Gateway Client ( call transaction /IWFND/GW_CLIENT to open SAP NW Gateway client)

Append $metatda to base service URL and press execute button. If everything is fine then you will HTTP

Response as below. Metadata provides information such as Entity type, key property, properties and Entity Set

name and also check service document append ?$format=xml.

 

metadata.PNGservice doc.PNG

 

 

Build Types for Deep Entity

 

build-deep-str.PNGbuild-deep-str2.PNG

 

Code Snippet


*----------------------------------------------------------------------*
*       CLASS ZCL_ZPROJ_GR_MULTIDEEP_MPC_EXT DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS zcl_zproj_gr_multideep_mpc_ext DEFINITION
PUBLIC
INHERITING FROM zcl_zproj_gr_multideep_mpc
CREATE PUBLIC .

PUBLIC SECTION.

TYPES :
BEGIN OF ts_deep_entity,
id TYPE char10,
name
TYPE char30,
name2
TYPE char30,
headitemo
TYPE STANDARD TABLE OF ts_itemo WITH DEFAULT KEY,
headitemt
TYPE STANDARD TABLE OF ts_itemt WITH DEFAULT KEY,
END OF ts_deep_entity.

METHODS define
REDEFINITION
.

 

Redefine the DEFINE method of Extended Model Provider class ZCL_ZPROJ_GR_MULTIDEEP_MPC_EXT

 

 

red-mpc.PNG


Code Snippet


METHOD define.
super
->define( ).
DATA:
lo_annotation    
TYPE REF TO /iwbep/if_mgw_odata_annotation,
lo_entity_type   
TYPE REF TO /iwbep/if_mgw_odata_entity_typ,
lo_complex_type  
TYPE REF TO /iwbep/if_mgw_odata_cmplx_type,
lo_property      
TYPE REF TO /iwbep/if_mgw_odata_property,
lo_entity_set    
TYPE REF TO /iwbep/if_mgw_odata_entity_set.

***********************************************************************************************************************************
*   ENTITY - Deep Entity
***********************************************************************************************************************************

lo_entity_type
= model->get_entity_type( iv_entity_name = 'Header' ). "#EC NOTEXT

lo_entity_type
->bind_structure( iv_structure_name  = 'ZCL_ZPROJ_GR_MULTIDEEP_MPC_EXT=>TS_DEEP_ENTITY' ). "#EC NOTEXT

ENDMETHOD
.


Now we have create one custom method (CUSTOME_CREATE_DEEP_ENTITY) in class ZCL_ZPROJ_GR_MULTIDEEP_DPC_EXT



CUSTOM-MET-1.PNGCUST-2-SIGN.PNG


IV_ENTITY_NAME                         Importing            Type      STRING

IV_ENTITY_SET_NAME                 Importing            Type      STRING

IV_SOURCE_NAME                       Importing            Type      STRING

IT_KEY_TAB                                   Importing            Type      /IWBEP/T_MGW_NAME_VALUE_PAIR

IT_NAVIGATION_PATH                Importing            Type      /IWBEP/T_MGW_NAVIGATION_PATH

IO_EXPAND                                   Importing            Type Ref To        /IWBEP/IF_MGW_ODATA_EXPAND

IO_TECH_REQUEST_CONTEXT    Importing            Type Ref To        /IWBEP/IF_MGW_REQ_ENTITY_C

IO_DATA_PROVIDER                    Importing            Type Ref To        /IWBEP/IF_MGW_ENTRY_PROVIDER

ER_DEEP_ENTITY                           Exporting             Type      ZCL_ZPROJ_GR_MULTIDEEP_MPC_EXT=>TS_DEEP_ENTITY


/IWBEP/CX_MGW_BUSI_EXCEPTION

/IWBEP/CX_MGW_TECH_EXCEPTION

 

 

Code Snippet

 

METHOD custome_create_deep_entity.

 
DATA: lr_deep_entity TYPE zcl_zproj_gr_multideep_mpc_ext=>ts_deep_entity,
lt_itemo
TYPE zcl_zproj_gr_multideep_mpc=>tt_itemo,
lt_itemt
TYPE zcl_zproj_gr_multideep_mpc=>tt_itemt,
ls_itemo
TYPE zcl_zproj_gr_multideep_mpc=>ts_itemo,
ls_itemt
TYPE zcl_zproj_gr_multideep_mpc=>ts_itemt.

DATA : ls_general_data TYPE zstr1_header,
lt_itemo_data
TYPE STANDARD TABLE OF zstr1_itemo,
ls_itemo_data
TYPE  zstr1_itemo,
lt_itemt_data
TYPE STANDARD TABLE OF zstr1_itemt,
ls_itemt_data
TYPE  zstr1_itemt.

FIELD-SYMBOLS: <ls_itemo> TYPE zcl_zproj_gr_multideep_mpc=>ts_itemo,
<ls_itemt>
TYPE zcl_zproj_gr_multideep_mpc=>ts_itemt.
 
*  Transform data into the internal structure

io_data_provider
->read_entry_data(
IMPORTING
es_data
= lr_deep_entity ).
 
**********Collect the header fields here
ls_general_data
-id = lr_deep_entity-id.
ls_general_data
-name1 = lr_deep_entity-name.
ls_general_data
-name2 = lr_deep_entity-name2.

********Collect  itemO fields
LOOP AT lr_deep_entity-headitemo ASSIGNING <ls_itemo>.
CLEAR  ls_itemo_data.
ls_itemo_data
-id = <ls_itemo>-ido.
ls_itemo_data
-name = <ls_itemo>-nameo.
APPEND  ls_itemo_data TO lt_itemo_data.
ENDLOOP.

*******Collect itemT fields
LOOP AT lr_deep_entity-headitemt ASSIGNING <ls_itemt>.
CLEAR  ls_itemt_data.
ls_itemt_data
-id = <ls_itemt>-idt.
ls_itemt_data
-name = <ls_itemt>-namet.
APPEND  ls_itemt_data TO lt_itemt_data.
ENDLOOP.
 
********Call RFC
 
CALL FUNCTION 'ZDEEP_RFC'
EXPORTING
ls_header
= ls_general_data
TABLES
lt_itemo 
= lt_itemo_data
lt_itemt 
= lt_itemt_data.

er_deep_entity
-id = ls_general_data-id.
er_deep_entity
-name = ls_general_data-name1.
 
ENDMETHOD
.



Now we have to Redefine the method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_DEEP_ENTITY


red-createdeep.PNG


Code Snippet



METHOD /iwbep/if_mgw_appl_srv_runtime~create_deep_entity.

DATA custome_create_deep_entity TYPE zcl_zproj_gr_multideep_mpc_ext=>ts_deep_entity.

CASE iv_entity_set_name.
*-------------------------------------------------------------------------*
*             EntitySet -  HeaderSet
*-------------------------------------------------------------------------*
WHEN 'HeaderSet'.
*       Call the entity set generated method
*      TRY.

CALL METHOD me->custome_create_deep_entity
EXPORTING
iv_entity_name         
= iv_entity_name
iv_entity_set_name     
= iv_entity_set_name
iv_source_name         
= iv_source_name
it_key_tab             
= it_key_tab
it_navigation_path     
= it_navigation_path
io_expand              
= io_expand
io_tech_request_context
= io_tech_request_context

          io_data_provider        = io_data_provider
IMPORTING
er_deep_entity         
= custome_create_deep_entity.

copy_data_to_ref
(
EXPORTING
is_data
= custome_create_deep_entity
CHANGING
cr_data
= er_deep_entity
).
ENDCASE.
ENDMETHOD
.


Coding Part done!!!....Let's move to Testing



Testing


  • Select HTTP method as POST
  • Place the Request URI : /sap/opu/odata/sap/ZPROJ_GR_MULTIDEEP_SRV/HeaderSet
  • Place the External Break point at METHOD CUSTOME_CREATE_DEEP_ENTITY
  • Execute the Service (F8/Execute)


Request Payload

 

 

<?xml version="1.0" encoding="UTF-8"?>
<atom:entry
xmlns:atom=
"http://www.w3.org/2005/Atom"
xmlns:d=
"http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m=
"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<atom:content type=
"application/xml">
<m:properties>
<d:Id>100</d:Id>
<d:Name>Test</d:Name>
<d:Name2>Test Header2</d:Name2>
</m:properties>
</atom:content>
<atom:link
rel=
"http://schemas.microsoft.com/ado/2007/08/dataservices/related/HeadItemO"
type=
"application/atom+xml;type=feed"
title=
"ZPROJ_GR_MULTIDEEP_SRV.Header_ItemO">
<m:inline>
<atom:feed>
<atom:entry>
<atom:content type=
"application/xml">
<m:properties>
<d:IdO>10</d:IdO>
<d:NameO>Test Item11</d:NameO>
</m:properties>
</atom:content>
</atom:entry>
<atom:entry>
<atom:content type=
"application/xml">
<m:properties>
<d:IdO>20</d:IdO>
<d:NameO>Test Item12</d:NameO>
</m:properties>
</atom:content>
</atom:entry>
</atom:feed>
</m:inline>
</atom:link>
<atom:link
rel=
"http://schemas.microsoft.com/ado/2007/08/dataservices/related/HeadItemT"
type=
"application/atom+xml;type=feed"
title=
"ZPROJ_GR_MULTIDEEP_SRV.Header_ItemT">
<m:inline>
<atom:feed>
<atom:entry>
<atom:content type=
"application/xml">
<m:properties>
<d:IdT>10</d:IdT>
<d:NameT>Test Item21</d:NameT>
</m:properties>
</atom:content>
</atom:entry>
<atom:entry>
<atom:content type=
"application/xml"
>
<m:properties>
<d:IdT>20</d:IdT>
<d:NameT>Test Item22</d:NameT>
</m:properties>
</atom:content>
</atom:entry>
</atom:feed>
</m:inline>
</atom:link>
</atom:entry>

test-1.PNGbreak-1-testing.PNG

 

Before executing method read_entry_data values in lr_deep_entity is initial

brk-2-bfr.PNGbrk-2-bfr2.PNG


After executing method read_entry_data values in lr_deep_entity is not initial


aft-brk-1.PNGaft--brk-2.PNG


Now RFC Will receive the three structure values


rfc1.PNG


Once come out from the debugger ...record will be created in Backend.


succs.PNG

 



      ***************************   Your Done !!! **************************


      Appreciate your suggestions and comments.

Upcoming Webinar: Integration Gateway in SAP Mobile Platform 3.0

$
0
0


This session will introduce you to Integration Gateway and the unique value it adds to SAP Mobile Platform 3.0.


Integration Gateway is a reusable technology component that brings SAP one step closer to realizing its vision of delivering, a REST based, harmonized integration layer amongst all the solutions in SAP portfolio and beyond. To achieve that, Integration Gateway implements a runtime that supports various protocols and standards such as HTTP, ODC, SOAP, JPA and JDBC to access data. Furthermore, it comes with design-time tools that allow modelling and provisioning of new RESTful (OData) web services based on the data sources supported by the runtime. As a result, Integration Gateway complements SAP Gateway by provisioning (RESTful) OData services that expose data not only from any SAP system, but also non-SAP. Best of all, as a reusable component, Integration Gateway capabilities will be available across many SAP solutions consistently.


Please join us by clicking the applicable registration link below:


SAP Internal Employee Session Americas: 

May 14th, 2014  12:00 Noon - 1:00pm (EST)


SAP Internal Employee Session APJ:

May 15th, 2014  12:00 Noon - 1:00pm (SGT)


SAP External (Partners and Customers)* Session Americas:

May 21st, 2014 12:00 Noon - 1:00pm(EST)


SAP External (Partners and Customers)* Session APJ:

May 22nd, 2014  12:00 Noon - 1:00pm(SGT)

 

*Partner and Customers need an S-User for the registration. You can order the S-User here:  http://service.sap.com.

oData for Everything? may be not!

$
0
0

While building ui5 applications using oData, there were may instances where I had to make any adjustments to represent everything coming-out/going-into SAP in terms of oData. Most of the times, these were work-arounds thus telling me that oData is not the one-data-model-fits-all solution.

 

Think about a scenario where I need to validate a user entered VIN number on a UI5 application. All I require is a 'Valid' or 'Invalid' from this functionality. I can create an entity for VIN but that is an overkill for my functionality.

Some other scenarios I can think off are

     - “Update notes for a Sales Order”.

     - “Get drop down values/ dependent values ”

 

Wait! What about Function-Imports? Are they not designed for this exact purpose? Yes, they sound like. But either they return a complex type or an entity type or nothing at all. I do not want to create a complex type for knowing Valid/Invalid. Solution might be to allow Function-Import to return edm types, thoug NW Gateway is not yet supporting it (but part of oData 2.0 spec). Even with this feature, what about the various cover information part of the oData grammar? The other problem with the Function-Import is that it does not allow the request body, thus you need a work around even if you have a simple hierarchical information to be passed to the server.

 

I was going through HANA development training and found something useful. It allows creation of a XSJS service which solves most of these problems. I felt that HANA product has allowed XSJS services in addition to XSODATA services to suit exactly the scenarios I am talking about.

 

But we have ICF services in ABAP server which can do exactly the same by linking with an ABAP Class as request handler. But this would need enhancement to handle system aliases so that I can rout my ICF request from the Gateway system to the right back-end system. CSRF protection might be a good enhancement too.

 

Another solution would be to integrate the new ABAP push channel (Web-socket framework) to NW Gateway and allow it to make use of routing features.

But even with ICF services and ABAP Push channels not integrated with NW Gateway, UI5 developer can make use of these features for the scenarios I discussed, and need not always try to fit everything into an oData Entity.

How To: Enhancing an SAP Fiori App Gateway Service (PO Tracking)

$
0
0

SAP Fiori applications are pretty useful and user-friendly right out of the box.  Side-by-side with this initial usefulness is a set of tools and process that you can use to enhance and extend the delivered services with your own business logic.  As a developer, the first thing I wanted to do was mess around with stuff anyway - so it's nice to know that SAP built in ways for me to do that.

 

My colleague Gavin Quinn got our development environment set up with the available Fiori apps, and I just looked at one of them to try some enhancement stuff.  This is a very very simple example, but I wanted to present what I've done so folks can either learn for themselves or critique my work.  Hopefully a little of both.

 

Things you should note:

  • In this example, I'm using the Track Purchase Order application.  I'm tackling the service enhancements first, and will post later about the Fiori UI enhancement process. 
  • SAP publishes an overview of the apps.  Note that most of these ERP apps have separate pages detailing their extensibility and identify the specific enhancement points. 
  • This app is part of the first wave of Fiori apps.  I can't make any promises that this process will fit all next-gen apps, and in fact future releases of Fiori will probably follow a bit more standardized process for extensions - which I'll make sure to blog about when we get our hands on the next wave. 
  • I am following some of the things on this SAP page, but I have added some steps of my own as I discovered how to get this done.
  • To do the play-at-home version you need the appropriate Fiori installation set up in your ECC system.
  • After every step in enhancing things, I made sure to clean up cache on both my ECC and my Gateway systems.  I found that sometimes I didn't see the changes I wanted until I ran /IWBEP/CACHE_CLEANUP on both systems.  I recommend this as a general step in creating enhancement to the services - it seems to be something that comes up occasionally enough that it saved me time to just keep clearing it.

 

Scenario

The Track Purchase Order app lets you view PO/items/item detail for selected POs.  In the screenshot below, I have chosen the first item from one of our test POs and navigated to the item detail page.  You can see that the item is delivered to one of the plants in our system.  I am going to enhance the backend logic to include the distribution channel for that plant.

PO item detail.PNG

 

Enhancing the entity

If you navigate to SEGW in your ERP system and open project SRA020_PO_TRACKING, you'll see all the entity types available to this service.  The item detail page has its basis in the POItemDetailData entity, which is the entity we'll enhance.

po item detail entity.PNG

 

Instead of redefining the service and editing the entity directly like you would probably do for a custom-developed scenario, we have to edit a data dictionary structure and implement a couple of BAdIs.

 

The ABAP dictionary structure that defines this entity is SRA020_S_PO_ITEM_DETAILED.  If you open that structure and scroll to the bottom of the components list, you'll see that SAP has provided an append SRA020_S_PO_ITEM_DETAILED_INCL.  For my purposes I opened this include and created a customer append that held the field I wanted (vtweg, the distribution channel).

 

append structure for PO thing.PNG

 

Next, you'll need to create an implementation of BAdI SRA020_PO_TRACKING_MPC.  This provides the code hooks to update the runtime definition of the structures of the service.  Go to t-code SE18 and enter the BAdI name in the "BAdI Name" field.

 

Create an implementation with whatever naming conventions your organization uses.  Eventually you'll be led to implement method ENHANCE_GW_SERVICE_ENTITY_MPC in your implementation class.  The simple code I used below will accomplish adding the field to the entity at runtime.

 

METHOD if_sra020_po_tracking_mpc~enhance_gw_service_entity_mpc. 

 

  DATA: lo_property TYPE REF TO /iwbep/if_mgw_odata_property. 

 

  IF iv_entity_type_name = 'POItemDetailData'. 

   lo_property = io_entity_type->create_property( 

           iv_property_name = 'VTWEG' 

           iv_abap_fieldname = 'VTWEG' ). 

 

   lo_property->set_nullable( abap_true ). 

  ENDIF. 

 

ENDMETHOD.

 

At this point, you should be able to see a (blank) VTWEG field in your Gateway service.  As part of getting the Fiori application installed you will end up with a service you can test in Gateway from t-code /IWFND/GW_CLIENT.


 

Getting data at runtime

Now that there's a field in the entity to be a placeholder for the data you want to add, you can implement a different BAdI to fill the live system data you want to into this field.  Once again, t-code SE18 is your friend; enter BAdI SRA020_PO_TRACKING_DPC and do the same stuff.

 

When it's time to implement your code, you'll notice that this BAdI has a lot more available methods.  For the data we want to monkey around with, method CHANGE_POITEMDETAILDATA_API suits our needs.  Code I used:

 

METHOD if_sra020_po_tracking_dpc~change_poitemdetaildata_api. 

 

  TYPES: BEGIN OF ltyp_vtweg, 

       werks TYPE werks_d, 

       vtweg TYPE vtwiv, 

      END OF ltyp_vtweg. 

 

  DATA: lt_vtweg TYPE TABLE OF ltyp_vtweg, 

     ls_vtweg TYPE ltyp_vtweg, 

     lv_vtweg TYPE vtwiv, 

     lt_werks TYPE RANGE OF werks_d, 

     ls_werks LIKE LINE OF lt_werks. 

 

  FIELD-SYMBOLS: <ls_po_items_details> LIKE LINE OF ct_po_items_details. 

 

  LOOP AT ct_po_items_details ASSIGNING <ls_po_items_details>. 

   CLEAR ls_werks. 

   ls_werks-sign = 'I'. 

   ls_werks-option = 'EQ'. 

   ls_werks-low = <ls_po_items_details>-plant. 

   APPEND ls_werks TO lt_werks. 

  ENDLOOP. 

 

  CHECK lt_werks IS NOT INITIAL. 

 

  SELECT werks vtweg INTO CORRESPONDING FIELDS OF TABLE lt_vtweg 

   FROM t001w 

   WHERE werks IN lt_werks. 

 

  CHECK lt_vtweg IS NOT INITIAL. 

 

  SORT lt_vtweg BY werks. 

  LOOP AT ct_po_items_details ASSIGNING <ls_po_items_details>. 

   READ TABLE lt_vtweg INTO ls_vtweg WITH KEY 

    werks = <ls_po_items_details>-plant BINARY SEARCH. 

   IF sy-subrc IS INITIAL. 

    <ls_po_items_details>-vtweg = ls_vtweg-vtweg. 

   ENDIF. 

  ENDLOOP. 

 

ENDMETHOD. 

 

I hope it's obvious here that I'm just taking the PO items' plant (werks) and using that to select on T100W to get the plant's associated distribution channel.  The changing parameter CT_PO_ITEMS_DETAILS has the fields we need to change.

 

After implementing the DPC BAdI you're all done.  You should see the field come into the service data and filled with the appropriate distribution channel.  Proof:

vtweg proof.PNG

 

Hope this helps!  Remember, this doesn't get you all the way there - you still have to update your UI5 to reveal that field on your screen.  I'll be researching that soon and presenting what I find. 

Open Data Protocol

$
0
0

Open Data Protocol

Open Data Protocol (OData) is a data access protocol initially defined by Microsoft. Versions 1.0, 2.0, and 3.0 are released under the Microsoft Open Specification Promise. Version 4.0 is being standardized at OASIS,[1] and was released in March 2014.[2]

The protocol was designed to provide standard CRUD access to a data source via a website. It is similar to JDBC and ODBC although OData is not limited to SQL databases.

 

Architecture

OData is built on the AtomPub protocol and JSON where the Atom structure is the envelope that contains the data returned from each OData request. An OData request uses theREST model for all requests. Each REST command is a POST, GET, PUT, PATCH, or DELETE http request (mapping to CRUD) where the specifics of the command are in the url.

  • GET: Get a collection of entities (as a feed document) or a single entity(as an entry document).
  • POST: Create a new entity from an entry document.
  • PUT: Update an existing entity with an entry document.
  • PATCH: Update an existing entity with a partial entry document.
  • DELETE: Remove an entity.

Any platform that provides support for HTTP and XML is enough to form HTTP requests to interact with AtomPub. The OData specification defines how AtomPub is used to standardize a typed, resource-oriented CRUD interface for manipulating data sources.

 

Typical Workflow When Creating a New User Interface:-

1.png

2.png


3.png

 

Architectural Stack for online Application:-

 

4.png

 

Service Builder – Data Model:-

Create / Model OData  

Artifacts --

  • Entity Types 
  • Entity Sets     
  • Complex Types
  • Associations
  • Association Sets
  • Function Imports    

5.png                                   

-

Generation of runtime objects :-

 

 

6.png

 

 

Service implementation – CRUD methods:-

Direct navigation into the CRUD –

Methods--

  • Create
  • Read and Query
  • Update
  • Delete

 

7.png

8.png

 

Service Builder – runtime artifacts:-

ABAP classes for

  • Model definition
  • Service implementation

Service registration in the

backend


9.png

Service Builder – Result  :-

16.png

/iwfnd/maint_service :-

11.png

 

Service document in the browser and entity types in

SEGW

12.png

 

$metadata document

http://<host>:<port>/sap/opu/odata/sap/ZCD204_EPM_LECTURE_SRV/$metadata

13.png

 

Summary - Transactions you should know as a developer

 

14.png

Gateway Service Builder - development flow in detail

15.png

How to solve language issues in Android app, generated by GWPA

$
0
0

Intro


Within this Blog post, I’d like to share with you the trouble I had – and the solution for it.

 

 

 

Background


I had generated an Android application with SAPGateway Productivity Accelerator (GWPA).
For more information about GWPA please refer to the link section below.

The application connects to an SAP Backend on which Gateway is installed.
The application uses an API that was generated by GWPA.
The aim is to consume Backend-data, which is provided based on the ODATA protocol

When I ran the application on my real device, the backend data was provided in a different language than expected.
In my personal case, it was German.
The issue is not about the concrete language, or about existing or not existing translation of the backend data, short texts, descriptions, etc.
The problem is about how to control the language in which data is returned by the service-call.


Details

 

In my SAP Backend, there’s a Gateway Service.
Built in ABAP, the implementation of the Gateway Service uses BAPIs and RFCs in order to retrieve the desired backend data.
The data is then provided based the ODATA protocol, and can be accessed via the internet.
When requesting the Backend data via a Service call,  a URL is invoked, so the service can be explored with a simple Internet Browser, like e.g. Chrome, Firefox or the Internet Explorer.
In order to access the data, the browser fires an HTTP-request. For reading data it is a GET request.
When requesting data from the SAP Backend, a valid user in the respective system is usually required.
Such a user can have a default logon-language, according to his location and preferences.

 

1) The user logs into the SAP Backend System and provides his langage.
The result is: the data is presented in the desired language

 

2) When executing a service call, the language can be controlled with a parameter that is appended to the URL, after the question mark.
The following example tells the service to deliver the backend data in German translation, if available.

 

?&sap-language=de

 

3) Now, instead of calling the service with the browser, a typical use case is to consume the data with a mobile application.

To make life easy, SAP has provided the GWPA, a toolset that is installed in Eclipse and allows to generate a mobile application with just a few clicks.

Please find a tutorial mentioned in the link section below.


In my case, I used GWPA and happily generated an Android application.

Right after generation, the app could be launched and provided the desired data.

I launched the app on my real device, my real smartphone connected to my (real) PC via (real) USB cable.

I mean: I didn’t use the Android emulator. This makes a difference.


Soon after the first happiness about the successful retrieval of data, I got the first trouble:

The data looked strange…

Some properties were empty, others had strange German texts.

So it looked like the logon happened in German language and some texts were simply not translated (therefore empty), others weren’t properly translated, probably because the connected backend wasn't a productive system.

But why was the data delivered in German?


I set the default logon language of the specified user in the SAP Backend to English, without success.

I carefully checked the code: obviously, the generated code didn’t explicitly set the language to German.

I carefully checked the Android log file: no hint about a specific language setting.

It looked like the device-language was used.

 

What now?

 

 

The solution

 

So I had to control the language in my GWPA-based Android app.
After some research in the API that is provided by GWPA, the solution is to add the following 2 lines to the generated code:

 

requestHandler.getConnectivityHelper().setSendLanguageHeader(false);
requestHandler.getConnectivityHelper().getParameters().setLanguage("en");

 

That’s the solution.

 

The remaining question is: where to place these 2 lines?


The code snippets show that the generated Android application provides an object called RequestHandler which provides support for programmatically executing service calls to the service URL that is defined in the application.
It also provides one single entry for all the configuration that is required for executing service calls: e.g. the SAP backend-client, the user, the desired format (json or atom), the service-URL, etc
As a consequence, it is also the right place to configure the language settings.

In the generated code, the instance of the RequestHandler is obtained in the onCreate() method of the launcher-Activity .
You can also search the generated code for the member-variable named “requestHandler”.
Please note: since the RequestHandler is bound to the service, the name of the Java class is generated as a concatenation of service name and “RequestHandler”.

Example:  <MYSERVICENAME>RequestHandler

 

Once you’ve found the place where the RequestHandler is instantiated and configured, you can simply add the 2 lines mentioned above.

 


Alternative

 

The object com.sap.gwpa.proxy.connectivity.SDMConnectivityHelper provides access to the instance of com.sap.mobile.lib.request.ConnectivityParameters, which contains a specific method setLanguage() for the language parameter.
If you need to set an own custom parameter, you have a different option.

 

The object where you can get access to the URL in order to add your own parameters is the com.sap.gwpa.proxy.ODataQuery object.
The instance of this object is used in the generated methods of the RequestHandler.
As expected, the RequestHandler contains methods which correspond to the HTTP operations: GET, POST, DELETE, etc
Examples:


createProductSetEntry()
loadSalesOrderSet()
deleteBusinessPartnerSetEntry()

 

Each of such methods deals with the ODataQuery instance.
There, you can add your own parameter.
Example:

query.addParameter("sap-language", "en");


 

 

Conclusion

 

I hope that this blog post has been able to help anybody to get comfortable with configuring the code generated by GWPA.

If you have any suggestion or correction, please add it to the comment-section below.

Thanks.

 

 

Links

 

GWPA introduction: http://scn.sap.com/community/netweaver-gateway/blog/2013/05/10/new-gateway-tool--sap-netweaver-gateway-productivity-accelerator
GWPA announcement: http://scn.sap.com/community/netweaver-gateway/blog/2013/06/03/gateway-productivity-accelerator-10-launched
Getting started with GWPA: Prerequisites
Getting started with GWPA: Android Preparation
Tutorial for Android Starter Application: http://scn.sap.com/community/netweaver-gateway/blog/2012/07/18/developing-an-android-app-consuming-data-from-sap-is-just-a-few-clicks-away

Initiatives on integrating Google Apps with SAP Gateway

$
0
0

If you are familiar with NetWeaver Gateway, you know how Gateway can be open and flexible to connect devices, environments and platforms with any programming languages by leveraging REST services and OData protocol. Gateway has been widely adopted by many SAP products such Fiori, Duet Enterprise for Microsoft SharePoint, SAP Mobile Platform, SAP Lumira, etc.

 

With more enterprise companies using Google Apps (like Gmail, Docs, Sheets, etc.) in their daily business, the growing demand of consuming data from SAP to Google Apps shows its potential in the market.  Last fall, we had the opportunity to explore this Google integration channel with Gateway with 2 SAP customers in the U.S.

 

Initially, from SAP side, we provided the test landscape maintained by the SAP Developer Center. Then, Google team had successfully consumed a service of Product object as an example to display product information in the Google Sheets from SAP ERP system. The Google Apps runs on their Google cloud technology consume the REST services exposed by SAP NetWeaver Gateway. This shows huge potential of improving the productivity for our customers and even customers’ customers when more data from SAP can be accessed through Google Apps via cloud or mobility.

 

 

sap-goog-integration.png

 

The proof-of-concept projects are underway.  We are collaborating with Google and the customers as co-innovation projects identifying the following scenarios for the projects:

1. Create and update data in SAP backend using Google forms / Docs

2. Generate report in Google Sheets

3. SAP Workflow approval via Gmail client

 

On the other hand, for SAP Partners who build and sell enterprise solutions with SAP and Google technologies, they can participate in our new 2014 SAP and Google Application Challenge. Participating members will receive enablement and certification support. The finialists will get a chance to win a pair of Google Glass as well. For more details, check the page here.

https://www.sapappsdevelopmentpartnercenter.com/en/apps-challenges/


How To: Enhancing an SAP Fiori App Gateway Service (PO Tracking)

$
0
0

SAP Fiori applications are pretty useful and user-friendly right out of the box.  Side-by-side with this initial usefulness is a set of tools and process that you can use to enhance and extend the delivered services with your own business logic.  As a developer, the first thing I wanted to do was mess around with stuff anyway - so it's nice to know that SAP built in ways for me to do that.

 

My colleague Gavin Quinn got our development environment set up with the available Fiori apps, and I just looked at one of them to try some enhancement stuff.  This is a very very simple example, but I wanted to present what I've done so folks can either learn for themselves or critique my work.  Hopefully a little of both.

 

Things you should note:

  • In this example, I'm using the Track Purchase Order application.  I'm tackling the service enhancements first, and will post later about the Fiori UI enhancement process. 
  • SAP publishes an overview of the apps.  Note that most of these ERP apps have separate pages detailing their extensibility and identify the specific enhancement points. 
  • This app is part of the first wave of Fiori apps.  I can't make any promises that this process will fit all next-gen apps, and in fact future releases of Fiori will probably follow a bit more standardized process for extensions - which I'll make sure to blog about when we get our hands on the next wave. 
  • I am following some of the things on this SAP page, but I have added some steps of my own as I discovered how to get this done.
  • To do the play-at-home version you need the appropriate Fiori installation set up in your ECC system.
  • After every step in enhancing things, I made sure to clean up cache on both my ECC and my Gateway systems.  I found that sometimes I didn't see the changes I wanted until I ran /IWBEP/CACHE_CLEANUP on both systems.  I recommend this as a general step in creating enhancement to the services - it seems to be something that comes up occasionally enough that it saved me time to just keep clearing it.

 

Scenario

The Track Purchase Order app lets you view PO/items/item detail for selected POs.  In the screenshot below, I have chosen the first item from one of our test POs and navigated to the item detail page.  You can see that the item is delivered to one of the plants in our system.  I am going to enhance the backend logic to include the distribution channel for that plant.

PO item detail.PNG

 

Enhancing the entity

If you navigate to SEGW in your ERP system and open project SRA020_PO_TRACKING, you'll see all the entity types available to this service.  The item detail page has its basis in the POItemDetailData entity, which is the entity we'll enhance.

po item detail entity.PNG

 

Instead of redefining the service and editing the entity directly like you would probably do for a custom-developed scenario, we have to edit a data dictionary structure and implement a couple of BAdIs.

 

The ABAP dictionary structure that defines this entity is SRA020_S_PO_ITEM_DETAILED.  If you open that structure and scroll to the bottom of the components list, you'll see that SAP has provided an append SRA020_S_PO_ITEM_DETAILED_INCL.  For my purposes I opened this include and created a customer append that held the field I wanted (vtweg, the distribution channel).

 

append structure for PO thing.PNG

 

Next, you'll need to create an implementation of BAdI SRA020_PO_TRACKING_MPC.  This provides the code hooks to update the runtime definition of the structures of the service.  Go to t-code SE18 and enter the BAdI name in the "BAdI Name" field.

 

Create an implementation with whatever naming conventions your organization uses.  Eventually you'll be led to implement method ENHANCE_GW_SERVICE_ENTITY_MPC in your implementation class.  The simple code I used below will accomplish adding the field to the entity at runtime.

 

METHOD if_sra020_po_tracking_mpc~enhance_gw_service_entity_mpc. 

 

  DATA: lo_property TYPE REF TO /iwbep/if_mgw_odata_property. 

 

  IF iv_entity_type_name = 'POItemDetailData'. 

   lo_property = io_entity_type->create_property( 

           iv_property_name = 'VTWEG' 

           iv_abap_fieldname = 'VTWEG' ). 

 

   lo_property->set_nullable( abap_true ). 

  ENDIF. 

 

ENDMETHOD.

 

At this point, you should be able to see a (blank) VTWEG field in your Gateway service.  As part of getting the Fiori application installed you will end up with a service you can test in Gateway from t-code /IWFND/GW_CLIENT.


 

Getting data at runtime

Now that there's a field in the entity to be a placeholder for the data you want to add, you can implement a different BAdI to fill the live system data you want to into this field.  Once again, t-code SE18 is your friend; enter BAdI SRA020_PO_TRACKING_DPC and do the same stuff.

 

When it's time to implement your code, you'll notice that this BAdI has a lot more available methods.  For the data we want to monkey around with, method CHANGE_POITEMDETAILDATA_API suits our needs.  Code I used:

 

METHOD if_sra020_po_tracking_dpc~change_poitemdetaildata_api. 

 

  TYPES: BEGIN OF ltyp_vtweg, 

       werks TYPE werks_d, 

       vtweg TYPE vtwiv, 

      END OF ltyp_vtweg. 

 

  DATA: lt_vtweg TYPE TABLE OF ltyp_vtweg, 

     ls_vtweg TYPE ltyp_vtweg, 

     lv_vtweg TYPE vtwiv, 

     lt_werks TYPE RANGE OF werks_d, 

     ls_werks LIKE LINE OF lt_werks. 

 

  FIELD-SYMBOLS: <ls_po_items_details> LIKE LINE OF ct_po_items_details. 

 

  LOOP AT ct_po_items_details ASSIGNING <ls_po_items_details>. 

   CLEAR ls_werks. 

   ls_werks-sign = 'I'. 

   ls_werks-option = 'EQ'. 

   ls_werks-low = <ls_po_items_details>-plant. 

   APPEND ls_werks TO lt_werks. 

  ENDLOOP. 

 

  CHECK lt_werks IS NOT INITIAL. 

 

  SELECT werks vtweg INTO CORRESPONDING FIELDS OF TABLE lt_vtweg 

   FROM t001w 

   WHERE werks IN lt_werks. 

 

  CHECK lt_vtweg IS NOT INITIAL. 

 

  SORT lt_vtweg BY werks. 

  LOOP AT ct_po_items_details ASSIGNING <ls_po_items_details>. 

   READ TABLE lt_vtweg INTO ls_vtweg WITH KEY 

    werks = <ls_po_items_details>-plant BINARY SEARCH. 

   IF sy-subrc IS INITIAL. 

    <ls_po_items_details>-vtweg = ls_vtweg-vtweg. 

   ENDIF. 

  ENDLOOP. 

 

ENDMETHOD. 

 

I hope it's obvious here that I'm just taking the PO items' plant (werks) and using that to select on T100W to get the plant's associated distribution channel.  The changing parameter CT_PO_ITEMS_DETAILS has the fields we need to change.

 

After implementing the DPC BAdI you're all done.  You should see the field come into the service data and filled with the appropriate distribution channel.  Proof:

vtweg proof.PNG

 

Hope this helps!  Remember, this doesn't get you all the way there - you still have to update your UI5 to reveal that field on your screen.  I'll be researching that soon and presenting what I find. 

How to solve language issues in Android app, generated by GWPA

$
0
0

Intro


Within this Blog post, I’d like to share with you the trouble I had – and the solution for it.

 

 

 

Background


I had generated an Android application with SAPGateway Productivity Accelerator (GWPA).
For more information about GWPA please refer to the link section below.

The application connects to an SAP Backend on which Gateway is installed.
The application uses an API that was generated by GWPA.
The aim is to consume Backend-data, which is provided based on the ODATA protocol

When I ran the application on my real device, the backend data was provided in a different language than expected.
In my personal case, it was German.
The issue is not about the concrete language, or about existing or not existing translation of the backend data, short texts, descriptions, etc.
The problem is about how to control the language in which data is returned by the service-call.


Details

 

In my SAP Backend, there’s a Gateway Service.
Built in ABAP, the implementation of the Gateway Service uses BAPIs and RFCs in order to retrieve the desired backend data.
The data is then provided based the ODATA protocol, and can be accessed via the internet.
When requesting the Backend data via a Service call,  a URL is invoked, so the service can be explored with a simple Internet Browser, like e.g. Chrome, Firefox or the Internet Explorer.
In order to access the data, the browser fires an HTTP-request. For reading data it is a GET request.
When requesting data from the SAP Backend, a valid user in the respective system is usually required.
Such a user can have a default logon-language, according to his location and preferences.

 

1) The user logs into the SAP Backend System and provides his langage.
The result is: the data is presented in the desired language

 

2) When executing a service call, the language can be controlled with a parameter that is appended to the URL, after the question mark.
The following example tells the service to deliver the backend data in German translation, if available.

 

?&sap-language=de

 

3) Now, instead of calling the service with the browser, a typical use case is to consume the data with a mobile application.

To make life easy, SAP has provided the GWPA, a toolset that is installed in Eclipse and allows to generate a mobile application with just a few clicks.

Please find a tutorial mentioned in the link section below.


In my case, I used GWPA and happily generated an Android application.

Right after generation, the app could be launched and provided the desired data.

I launched the app on my real device, my real smartphone connected to my (real) PC via (real) USB cable.

I mean: I didn’t use the Android emulator. This makes a difference.


Soon after the first happiness about the successful retrieval of data, I got the first trouble:

The data looked strange…

Some properties were empty, others had strange German texts.

So it looked like the logon happened in German language and some texts were simply not translated (therefore empty), others weren’t properly translated, probably because the connected backend wasn't a productive system.

But why was the data delivered in German?


I set the default logon language of the specified user in the SAP Backend to English, without success.

I carefully checked the code: obviously, the generated code didn’t explicitly set the language to German.

I carefully checked the Android log file: no hint about a specific language setting.

It looked like the device-language was used.

 

What now?

 

 

The solution

 

So I had to control the language in my GWPA-based Android app.
After some research in the API that is provided by GWPA, the solution is to add the following 2 lines to the generated code:

 

requestHandler.getConnectivityHelper().setSendLanguageHeader(false);
requestHandler.getConnectivityHelper().getParameters().setLanguage("en");

 

That’s the solution.

 

The remaining question is: where to place these 2 lines?


The code snippets show that the generated Android application provides an object called RequestHandler which provides support for programmatically executing service calls to the service URL that is defined in the application.
It also provides one single entry for all the configuration that is required for executing service calls: e.g. the SAP backend-client, the user, the desired format (json or atom), the service-URL, etc
As a consequence, it is also the right place to configure the language settings.

In the generated code, the instance of the RequestHandler is obtained in the onCreate() method of the launcher-Activity .
You can also search the generated code for the member-variable named “requestHandler”.
Please note: since the RequestHandler is bound to the service, the name of the Java class is generated as a concatenation of service name and “RequestHandler”.

Example:  <MYSERVICENAME>RequestHandler

 

Once you’ve found the place where the RequestHandler is instantiated and configured, you can simply add the 2 lines mentioned above.

 


Alternative

 

The object com.sap.gwpa.proxy.connectivity.SDMConnectivityHelper provides access to the instance of com.sap.mobile.lib.request.ConnectivityParameters, which contains a specific method setLanguage() for the language parameter.
If you need to set an own custom parameter, you have a different option.

 

The object where you can get access to the URL in order to add your own parameters is the com.sap.gwpa.proxy.ODataQuery object.
The instance of this object is used in the generated methods of the RequestHandler.
As expected, the RequestHandler contains methods which correspond to the HTTP operations: GET, POST, DELETE, etc
Examples:


createProductSetEntry()
loadSalesOrderSet()
deleteBusinessPartnerSetEntry()

 

Each of such methods deals with the ODataQuery instance.
There, you can add your own parameter.
Example:

query.addParameter("sap-language", "en");


 

 

Conclusion

 

I hope that this blog post has been able to help anybody to get comfortable with configuring the code generated by GWPA.

If you have any suggestion or correction, please add it to the comment-section below.

Thanks.

 

 

Links

 

GWPA introduction: http://scn.sap.com/community/netweaver-gateway/blog/2013/05/10/new-gateway-tool--sap-netweaver-gateway-productivity-accelerator
GWPA announcement: http://scn.sap.com/community/netweaver-gateway/blog/2013/06/03/gateway-productivity-accelerator-10-launched
Getting started with GWPA: Prerequisites
Getting started with GWPA: Android Preparation
Tutorial for Android Starter Application: http://scn.sap.com/community/netweaver-gateway/blog/2012/07/18/developing-an-android-app-consuming-data-from-sap-is-just-a-few-clicks-away

Initiatives on integrating Google Apps with SAP Gateway

$
0
0

If you are familiar with NetWeaver Gateway, you know how Gateway can be open and flexible to connect devices, environments and platforms with any programming languages by leveraging REST services and OData protocol. Gateway has been widely adopted by many SAP products such Fiori, Duet Enterprise for Microsoft SharePoint, SAP Mobile Platform, SAP Lumira, etc.

 

With more enterprise companies using Google Apps (like Gmail, Docs, Sheets, etc.) in their daily business, the growing demand of consuming data from SAP to Google Apps shows its potential in the market.  Last fall, we had the opportunity to explore this Google integration channel with Gateway with 2 SAP customers in the U.S.

 

Initially, from SAP side, we provided the test landscape maintained by the SAP Developer Center. Then, Google team had successfully consumed a service of Product object as an example to display product information in the Google Sheets from SAP ERP system. The Google Apps runs on their Google cloud technology consume the REST services exposed by SAP NetWeaver Gateway. This shows huge potential of improving the productivity for our customers and even customers’ customers when more data from SAP can be accessed through Google Apps via cloud or mobility.

 

 

sap-goog-integration.png

 

The proof-of-concept projects are underway.  We are collaborating with Google and the customers as co-innovation projects identifying the following scenarios for the projects:

1. Create and update data in SAP backend using Google forms / Docs

2. Generate report in Google Sheets

3. SAP Workflow approval via Gmail client

 

On the other hand, for SAP Partners who build and sell enterprise solutions with SAP and Google technologies, they can participate in our new 2014 SAP and Google Application Challenge. Participating members will receive enablement and certification support. The finialists will get a chance to win a pair of Google Glass as well. For more details, check the page here.

https://www.sapappsdevelopmentpartnercenter.com/en/apps-challenges/

Intelligent Automation for the Enterprise through SAP Gateway

$
0
0

Quantilus  is excited to have the SAP Gateway team showcase our demo apps at SAPPHIRE NOW 2014. Our mission has been to build innovative applications to streamline business workflows, and SAP Gateway has given us the perfect tool to utilize the power of cutting edge technologies like augmented reality and machine vision in practical business applications.

SAP Gateway has allowed us to focus on building our applications without having to spend time and effort on backend integration, since the integration is seamless and instantaneous.   As a result, our total development time for these products has been exceptionally quick.


Visual Showroom

3D product visualization using augmented reality

 

vissho.png

 

Visual Showroom is an app developed for retailers that allows customers to shop in a virtual 3D environment in the context of their real environment. Using a tablet or a smartphone, users view 3D catalog items in situ, and place orders directly from the app.

Practical applications for this include but are definitely not limited to:

  • Interior Decorating and Design - Customers can visualize an item exactly where they want to place it in their home or office.  They can view a couch against a wall in the living room, or an entertainment center across from it. Users can select different colors, textures and materials for the furniture and visualize in situ.
  • Clothing/Apparel – Customers can view renderings of clothing in different styles and colors on a 3D image of their own bodies. They can capture screenshots and compare different “looks” before placing orders online.
  • Accessories - Customers can visualize 3D renderings of watches, sunglasses, jewelry and other accessories against their own bodies or on others. This can now solve the eternal question of "This looks good on the screen, but how will it look on me?"

 

It is painstaking and time consuming process (even for a professional designer) to estimate the fit and look of a product in a space or on a person.  Visual Showroom gives your customers a very real idea of how things will fit and how they will look.


Visual Showroom Architecture:


SAP_arch.png



SAP Gateway is used to extract and display product information, their variants, inventory level, delivery date etc. SAP Gateway is also used to place orders directly from the application into the SAP Business Suite.

Visual Showroom is a multi-platform app, and is currently supported on iOS 7 (iPad 3 and above), and Android (most tablets and phones running Android 4.3 and above).

 

GoToWork

Wearable devices (Google Glass) for workflow automation

gotowrk.png


GoToWork is a Google Glass app developed to significantly increase the efficiency of technical support personnel using machine vision and a voice user interface. Technicians can interact with the app in multiple modes while maintaining focus on tasks with both hands free. The primary features of GoToWork are:

  • GoToWork uses advanced voice recognition technology, enabling users to work “hands-free”.
  • Machine Vision is used to scan and identify products and parts. Data points are compared to product data in SAP to uniquely identify products.
  • Technicians can get step-by-step instructions, watch instructional videos, or share their viewport with experts for diagnosis and troubleshooting.
  • Users can directly check for the availability of specific parts in inventory and place orders for replacement parts.

 

The features of GoToWork can be easily customized for various business scenarios, such as:

  • Assembly Instructions – Users can get instructions for assembling and installing a product (furniture, electronics, etc.) by scanning a code or the product packaging. Users can also identify missing parts in the package and order the parts through the app. 
  • Locating Products in a store - The app can guide a user to the physical location of a product (aisle, bin, etc.) in a store. Users can place an order for a product in-app and go to the store to pick it up – the app will act as a “store GPS”. 
  • User Guides – User can get instructions on how to use a device or equipment (kitchen appliances, exercise equipment, computers, etc.) Users can scan the equipment and have GoToWork guide them on proper usage. GoToWork can also provide cross-selling suggestions for users to purchase from within the app.

 

SAP Gateway is used to retrieve the 3D model from SAP and to receive product master data. SAP Gateway is also used to check inventory levels of products and parts, and to place orders directly through the GoToWork app.  


GoToWork is currently built for and deployed on Google Glass, and can be extended for use on other wearable Android-based hardware.

 

We look forward to demonstrating these applications at SAPPHIRE, receiving your feedback and answering any questions that you may have. Feel free to reach out to us at info@quantilus.com for information about our apps or about our experience working with SAP Gateway.

Recognizing file name and type in browser after downloading file from Netweaver Gateway

$
0
0

Let's consider that we have working solution of file download from gateway as it is described for example in this blog How to Read Photo from SAP system using SAP NetWeaver Gateway.

 

When we point to the file, browsers does not handle the file name correctly, as they consider $value as name of the file. Thus it is not comfortable to open the file. Also, file name is shown as $value too which is inconvenient for the user when he wants to save the file.

 

To solve this issue we can set content-disposition response header according to rfc 1806 to inline and set the name of file there. Then browser will be able to recognize the name, user can save it with the name as it is set in SAP system.

 

 

Here is the sample code of method GET_STREAM implementation:

METHOD /iwbep/if_mgw_appl_srv_runtime~get_stream.     DATA: ls_stream      TYPE ty_s_media_resource,           er_entity      TYPE REF TO data,           lr_entity      TYPE REF TO data,                      ls_file  TYPE cl_sample_mpc=>ts_file,           ls_lheader     TYPE ihttpnvp.     CASE iv_entity_name.       WHEN 'File'.
* Load ls_file info here         ls_stream-value = ls_file-content.         ls_stream-mime_type = ls_file-mime_type.         ls_lheader-name = 'Content-Disposition'.         ls_lheader-value = 'inline; filename="'.         CONCATENATE ls_lheader-value ls_file-file_name INTO ls_lheader-value.         CONCATENATE ls_lheader-value '"' INTO ls_lheader-value.         set_header( is_header = ls_lheader ).         copy_data_to_ref( EXPORTING is_data = ls_stream                           CHANGING  cr_data = er_stream ).     ENDCASE.   ENDMETHOD.
Viewing all 245 articles
Browse latest View live


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