Quantcast
Channel: SAP Gateway
Viewing all 137 articles
Browse latest View live

Maintain Data Concurrency in OData

$
0
0

Introduction

 

More than one user has access to the same entity and hence the same data in SAP Fiori applications. So how to prevent parallel edit access for users so as to prevent the data from being overwritten in flight.

 

There are three ways to lock records to manage the concurrency.

    1. Pessimistic

        In this scenario the application assumes that concurrent writes will occur and hence protects it by aggressively locking out resources. This can lead to deadlocks and also have some performance reduction as applications using the resource will have to wait in queue to apply its changes.

    2. Optimistic

        In this scenario the application assumes that the likelihood of a concurrent write is rare and so allows the operation to continue.

    3. Semi-optimistic

        This is a combination of pessimistic and optimistic concurrency controls. This kind of solution is used for very specific scenarios.

 

For Data Concurrency OData recommends implementing Entity tags or ETAG's. Since OData uses HTTP protocols and is stateless, it can use only optimistic concurrency control of data and only that is discussed in detail further in this paper.

 

 

Implementing ETags in SAP Gateway

 

SAP Gateway allows three ways to implement ETags.

 

1. A field based ETag (typically a timestamp)

When an entity is typically a subset of a database table and the database has a field that  maintains a timestamp to signify a change whenever the record changes, then that field could be included in the entity and can be used as the E-Tag.

 

In transaction SAP Gateway Service Builder (SEGW), at the Entity Types, you select a field as your ETag property. Save and re-generate the Service.

 

 

2. A full entity based ETag (typically a timestamp)


    The shortcoming of the above method is that, there are scenarios where only a few fields from a database is exposed in an entity model. But changes to the DB table in the backend can occur through various sources including background programming, manual changes through backend transactions etc. These backend changes might not have changed the Entity fields at all, but still that will be considered as a change.

 

    In such a scenario the full entity based ETag could be implemented.

 

    Include a Field ETAG with data element HASH160 into the entity. And use that field as the ETag property for the entity.

 

    Once all data for the entity is fetched the hash value calculation happens.

 

   

 

3. Partial entity based ETag

 

Whatever ETag method that we implement will apply for all operations except Create. There are scenarios where the get_entityset implementation and get_entity implementation of the same Entity might not have same ETag values. This is due to that fact that there are certain information in an Entity which will be costly to fetch during a get_entityset operation. In such a scenario the partial entity based ETag could be implemented.

 

    The implementation of partial entity based ETag is very similar to the full entity based Etag. The only change is the calculation of hash value.

 

    Here instead of passing the complete entity, you remove the values for fields that you do not want to be part of the hash value calculation and then call the calculate hash.

 

For eg:-

 

 

Using ETags in Fiori


 

Classic Scenario with Etags

 

 

 

 

During the get entity if a valid etag is provided and the entity has not changed then the server responds with return code 304 (Resource not modified). If the entity has changed then the new set of data is returned with return code 200.

 

 

If-None-Match: W/"'DBF5DD4DE0073002917521B7057C0826FC5A7F8E'"

 

 

if you do not want to check against an existing e-tag, but get the data anyway you can use '*' to get the data.

 

If-None-Match: *

 

 

Update/Merge/Delete Entity uses the http header variable If-Match

 

If a valid e-tag is provided, the OData infrastructure checks for the hash value by calling the get_entity and verifies the passed e-tag value. If it is successful the update/merge/delete operation proceeds without any issues. If the e-tag does not match then the server returns status code 412 (Precondition failed.).

 

Note 1:

    As a developer if you want to any how update the data from client (while using the SAP Gateway Client for testing purpose) then you can pass the If-Match value as a '*', which means the client will win and will update the data irrespective.

 

Note 2:

     During the Update/Merge/Delete options in case of a ETag get_entity call is made in the backend before the update call to verify the ETag value.



References

http://www.sdn.sap.com/irj/scn/go/portal/prtroot/docs/library/uuid/a004b815-e3bd-3210-f787-8c0b3c7c6d4c?QuickLink=index&overridelayout=true&60125247183608

 

 

https://msdn.microsoft.com/en-au/library/dd541486.aspx


How to expose Gateway Services via HCI OData Provisioning, and secure them using SAP API Management on HCP Trial - Part 1

$
0
0

There is already a very fine blog from Martin Bachmann explaining HANA Cloud Platform, the benefits of cloud and HCI Odata Provisioning in general, as well as the scenario for connecting SAP HCI OData Provisioning to an SAP Gateway system here How to connect the SAP Business Suite to the SAP HANA Cloud Platform using Gateway as a Service Trial Edition. However like so many things in the cloud, there are changes already, as soon as its published.

 

* - As a testament to constant change, mere days after creating this blog, it was announced that the name is now HCP OData Provisioning. In trial for now the name still shows as HCI OData Provisioning, but in future when the name is changed, please replace HCIODP with HCPODP as you read

 

I will not re-cover the informational content from Martin's Blog again, but I will be showing the updated screens for the most recent version.

 

If you have already configured HCI Odata Provisioning using Martin's blog, or on your own, and want to skip to the SAP API Management part, please copy down the URL path to your HCI Odata Provisioning Services and go to Part 2 of this blog.

 

A quick bit on "Why SAP API Management?"

SAP API Management does not replace SAP Gateway, and in fact, relies on SAP Gateway to expose data from SAP Backends. What SAP API Management adds is an enhancement of the capabilities provided by SAP Gateway. It can sit on top of a Gateway deployment in order to provide Secure and Scalable access, through security, and data management policies, as well as providing a developer engagement area. With a deployment on HCP, it is even easier, as a user of SAP Gateway only needs to install/run the IWBEP component of Gateway on their SAP Backend system, and use HCI OData Provisioning on HCP to connect to it, consuming the exposed OData endpoints directly in SAP API Management. Additionally SAP API Management can combine other data sources such as HANA XS or Non-SAP data together with Gateway exposed data, exposed via a single secure endpoint for developers to build impressive Apps.

 

But this walkthrough will focus on using HCI OData provisioning (hereafter referred to as HCIODP) to consume services exposed by SAP Gateway, and expose them as OData endpoints which will be consumed by SAP API Management as API Proxies.

 

 


PART I – Creating OData Endpoints in HCIODP

 

* Pre-Requisite: An account on an SAP Gateway system accessible via Internet. For this walk-through I will be using the SAP Developer Center ES4 system. Anyone can sign up for an account here: SAP NetWeaver Gateway Developer Center


1. Enabling HCIODP in Trial

 

Login to trial, check the Services section, under "Integration" i.e. In HCP Trial Account

 

HCP_Services_HCIODP.png

 

Click HCI OData Provisioning tile to enter service. Check status of service. If click status is "Not enabled" click the "Enable" button. Wait until you see service status change to Enabled.

 

HCP_HCIODP_Service_enablement.png

 

 

2. Configuring HCIODP Destination(s)

 

Click “Configure HCI OData provisioning” - This should bring up the “Destinations” tab under "Configure HCI OData Provisioning". Click “New Destination” in order to create the destination for the SAP Developer Center ES4 system.

 

Enter details for the Gateway system. All details, including login, and password will be those which you have registered on the Gateway system. E.g. for SAP Developer center ES4 system, see below:

 

HCIODP_ES4_Destination_Settings.png

 

After you save, wait until details are saved in system, which will be indicated by the configuration screen turning grey and no longer allowing input.

 


3. Configuring HCIODP Roles

 

Click the “Roles” tab to configure user access in HCIODP.

 

Select GW_Admin role, and click “Assign” below in the “Individual Users” section. This will authorize the user to enter the Admin window for HCIODP to configure available services, view logs, or configure Metadata options.

 

In the popup window, enter the SAP ID login information (P-User, S-User, I#, etc.) you will be using, and click "Assign"..

 

HCIODP_Roles_GWAdmin.png

 

Assign_GW_Admin_User.png

Repeat this process with the role GW_User, this will assign authorization for a user to consume the services configured on HCIODP (but not to access the Admin window).

Once complete, you should have a user assigned to both the roles GW_Admin and GW_User.

 

 

4. Configuring HCIODP Services

Click the “HCI OData Provisioning” link at the top of the window, to return to the HCIODP base screen

 

HCP_Cockpit_Return_Selection.png

Then click “Go to Service” from the base screen for HCIODP.

 

If everything worked correctly, this will open a new browser tab, for the HCIODP Admin screen. You may be prompted to enter SAP ID credentials, enter the credentials for the user configured in the GW_Admin role. After login the Admin screen should appear as below:

 

HCIODP_Main_Screen.png

 

To begin exposing services from Gateway system configured, click the "Register" button at the top of the screen to bring up the “Register Service” screen. Select the SAP Gateway system configured in Step 2 from the drop down list for Destinations, then click the icon of a Magnifying Glass next to “Search Services” to bring up a list of available Gateway Services.

 

HCIODP_Search_ES4_Services.png

 

Select the desired service to be exposed to API Management by clicking the empty box on the far left to highlight that selection. E.g. to select “GWDEMO” below:

 

HCIODP_Select_Service.png
Note: The box will fill blue when selected, and if you move the mouse cursor away, you will see the entire row is blue when selected. If this is not the case, the row was not properly selected.

 

Click the "Register" button, to register the selected service in HCIODP. The service should now appear in the list of Registered Services for HCIODP.

HCIODP_Registered_Service.png

 

Click “Open Service Document” for the newly added service, to test that the service is exposing data as expected. This will open a new browser tab, with service data in OData format. Copy down the URL in your browser bar for the service, this will be used as the Target endpoint for the API Proxy.

Repeat these steps above for each Gateway service you want to expose.

 

When you have completed registering services, the next step will be creating API proxies in SAP API Management, using HCIODP as the OData Target Endpoints, and the Services as the APIs in this case. This will be covered in Part 2.

 

 

For questions, feedback, concerns, feel free to leave a comment, or send us an E-Mail.


Also follow us online
SAP API ManagementSAP.com|SCN| YouTube

How to expose Gateway Services via HCI OData Provisioning, and secure them using SAP API Management on HCP Trial - Part 2

$
0
0

This is a continuation from Part 1 where we walk-through setting up HCI OData Provisioning on HANA Cloud Platform against SAP Developer Center'ss ES4 Gateway system. If you haven't already completed this, I recommend going through Part 1 in order to be ready for this blog.


Now that you should have at least one SAP Gateway service exposed in HCI OData Provisioning (hereafter referred to as HCIODP), it's time to set things up so that they can be connected to by SAP API Management. Due to the Platform nature of HANA Cloud Platform, this is remarkably easy fortunately. If you have not yet enabled SAP API Management, please follow the steps outlined here Free Trial of SAP API Management on HANA Cloud Platform is available now!

 

Once you are set-up, can get started right away.


PART II – Creating API Proxies from OData Endpoints in SAP API Management

 

1. Creating a "System" connection to HCIODP.


Login to your HCP Trial Account with SAP API Management enabled. Open the Services pane, and locate SAP API Management under the "Integration" section. Launch API Management API Portal by clicking "Access SAP API Management API Portal"

 

Launch_SAP_API_Mgmt_Portal.png

 

This should load the "Configure" section of SAP API Management by default, if not, click the drop down menu from the top left hand corner and select “Configure”. This is where one generates Target systems for SAP API Management. Click "Create" in the bottom right hand corner to add a system.

This will take you to the Create System window, where you will need to enter the relevant details for the HCIODP system used in Part I.


Title: HCIODP

Details: HCI OData Provisioning system, providing exposed Gateway Services

Host: enter the Base URL from the Service Document URL you saved from Part I. (The format will be gwaas-<userID>trial.hanatrial.ondemand.com)

Port: 443
Check Use SSL
Authentication Type:
Basic

Service Collection URL:  /CATALOGSERVICE/ServiceCollection

 

Create_New_System.png

 

* The Catalog URL is something unique to SAP Gateway systems, which allows SAP API Management to "Discover" available services from the Catalog Service. It is not used for Non-SAP systems.

 

After checking details entered, then click “Save”. Once system has been saved, click “Launch” hyperlink at bottom left-hand side of screen, this will launch a new tab, opening the SAP API Management Destinations area on the HCP Cockpit, not to be confused with the Global HCP Destinations. Here you will add Authentication settings for the newly created System. Click the name of the system you newly created, e.g. HCIODP and click the "Edit" button at the bottom of the page.

 

User: <Use the accountID that was added under GW_User in Part I>

Password: <Password for accountID added under GW_User in Part I>
Next, Click “New Property” under Additional Properties, and enter Key: TrustAll || Value: true

 

 

API_System_Details.png

Then click “Save”.Changes can take up to 5 minutes to save (but usually will only take a few seconds).

 

 

2. Creating an API Proxy using HCIODP Service

 

Close HCP Cockpit to return to API Management API Portal window. Select drop-down menu list from top left hand corner and select "Manage" to open API Proxy page.


API_Menu.png


In the API Proxy window, click “Create” at the bottom-right hand corner, and select “Create API” from popup selection to bring up the “Create API” screen.

Provider System: <Select system created in step 2>
Click “Discover” button to see a list of all services exposed by HCI-OData Provisioning.

Select a Service and click “OK” this should auto-fill all the API Information for you.

 

Create_API.png

* Link Target Server will create the API with all System information determined by the Provider System you determine, and all pathing linked as a virtual path. This allows for easy transition between environments (such as Dev, Test, Prod) for the API Proxy. Documentation flag determines whether SAP API Management attempts to pull existing documentation from the Service, and is only applicable for SAP Gateway endpoints.


Click “Create” to generate the API Proxy. If everything was entered correctly, the API Details screen should come up, with all Resources (and corresponding descriptions of the model) created automatically from the Metadata.

 

Create_API_full.png

 

Then click “Save”. If everything went well you should see a message at the bottom of the screen telling you "API Registered Successfully".

 

To test that the API Proxy is working correctly, click “GET” for one of the resources with that operation available. If no resources are available, select “Test” from the main Drop-Down menu, then select the name of the API Proxy from the list of APIs.

Click “Authentication: None” and select “Basic Authentication” from the drop down list.
User Name: <UserID added under GW_User in Part I>
Password: <Password for userID added under GW_User in Part I>
Select the “GET” operation.

 

Test_Console.png

 

Click “Send” in the bottom right hand corner.

This should successfully retrieve the OData Collection provided by HCIODP, via a call to the SAP API Management API Proxy Endpoint URL.

 

Now that you have an API Proxy sitting on top of the HCIODP service, you can start adding Policies to extend the functionality, as well as expose it to the Developer Portal so that Developers could begin to build apps on top of the data. I will not get into that in this blog, as we were just quickly getting up and running connecting SAP API Management to HCIODP.

 

If you would like to start learning more about what you can do with SAP API Management, I suggest looking at the repository of information SAP API Management - Overview & Getting started which will continue to be updated as more enablement content is added.

 

Of particular interest to this particular exercise, will be the Blog on creating a Policy SAP API Management - Enabling URL masking . If you notice above, the returned data includes links to the HCI OData Provisioning service, which is not what you want if SAP API Management is the intended target for connectivity. The linked blog will tell you how to have SAP API Management automatically mask all URLs through SAP API Management.

 

For questions, feedback, concerns, feel free to leave a comment, or send us an E-Mail.


Also follow us online
SAP API ManagementSAP.com|SCN| YouTube

Making your SAP Gateway work smarter not harder : 1) Developing Re-Use Patterns

$
0
0

Introduction


As SAP customers, partners and consultants embark on their journey to designing and building your own Fiori style applications a major part of this journey will be building your own RESTful API’s using SAP Gateway ( OData services ).

 

 

I'm going to break down my learning and insights into SAP Gateway development into a series of blogs where I would like to cover the following topics:

 

  • Re-Use and Development Patterns
  • Encapsulation of Business Logic & Searching for Entities
  • Performance
  • eTags for concurrency control

 

 

 

Acknowledgement and Use Cases


The development patterns covered in this series are not originally mine.  If you look at the My Accounts Fiori application delivered by SAP in CRM (UICRM001), this pattern was written to support the OData service "CRM_BUPA_ODATA".

 

Our colleagues who have put together this pattern probably don't realise how much of a gem it has been for me to rapidly produce re-usable, nicely encapsulated entity implementations in SAP Gateway, so hats off to the folk who put a lot of though and effort behind this.


You can consider this pattern when creating your own OData services in the customer namespace.  For modifying SAP delivered OData services you should always follow the SAP recommended approach and enhancement documentation.

 

 

 

Key Learnings from this article:

 

  • You need someone who understands how to build OData services in SAP Gateway they should know how to leverage re-use patterns to help accelerate UX development and multi-channel consumption.


  • You can build a generic template that seeds a base implementation for your concrete entities.


  • You can build a module specific abstract object where you can define re-usable functions on a module level (SD, MM, BP for example )


  • This is NOT the only way or the standard SAP way of building OData services, I just really like this pattern as it has served me enormously well on a large scale wall to wall Fiori project and I’m hoping to adopt it has a gold standard on future projects I work on and hope it helps you to accelerate your OData service development.

 

 

 

 

Putting the Pattern Together

 

First let’s cover our typical OData service from a high level and use a simple entity relationship model as an example ( Account or Business Partner with an Address association ):

 

blog_image.png

 

 

SEGW - Design Time.

 

Here we define our entities, attributes of those entities and association between them ( navigation path ).

 

In our example we want to look at two entities, Account and Address.  You can generate the entity with various methods but I like to generate new entities from a custom ABAP structure.

 

  • I like to start with a standard SAP structure as an Include ( BUT000 in this example )
  • I like to include the term "ODATA" in the naming convention to signify the structure is associated with a REST service that implies restricted use.

 

 

blog_image.png

 

 

 

DPC, DPC_EXT - Data Provider Classes


These are the classes that are generate from activating the OData service and where you have been told to implement you entity logic for CRUD functions.

 

I have a couple of rules around DPC_EXT:

 

  • Pass through implementation only for each entity CRUD function to an encapsulated class  
  • NO business logic in DPC, this should all be encapsulated in a concrete class
  • Function Imports should have their own API, in other words any implementation in EXECUTE_ACTION should be calling some API or utility type class.

 

 

 

 

Entity Implementation and Class Hierarchy


Most implementations I have seen have a loose encapsulation concept, in other words implementation in CRUD methods in the DPC_EXT class contain some business logic and other business logic is contained somewhere else.

 

I don’t like this as it becomes difficult to maintain and causes regression problems when new developers take over and add new features.

 

Instead we can use a nice class hierarchy that helps us encapsulate different business logic in layers. 

 

This is the current hierarchy I like:

 

 

blog_image.png

 

 

In context with our “Account” entity, this is what we would end up with:

 

 

blog_image.png

 

 

ZCL_ODATA_RT

This class provides a base line search for GET_ENTITYSET that handles skip / count / paging.  The base line search is based on a dyanmic SQL approach.  it also allows us to do eTag calculation across all out entities.  Apart from the Search pattern in this class, I only use it for Gateway framework type functions.

ZCL_ODATA_BP

I’ve called this a modular layer, we can encapsulate module specific functions.  In our use case for Accounts (Business Partner) we may have common functions such as add leading zeros to a BP number( internal / external display ) or functions that format the Business Partners full name that we can write once and call across any concrete class that belongs to our module.

ZC_ODATA_ACCOUNT

This is the concrete class, here you implement the CRUD functions GET_ENTITYSET, GET_ENTITY, UPDATE_ENTITY etc which are called from the corresponding methods in the actual DPC_EXT class of your service.  All entity specific business logic is maintained here.

 

 

 

Re-use of Entity Objects

 

Start thinking about the services you need to build.  Are there re-usable entities across these services? Let’s take a look at a one example.

 

Below is a diagram that shows two OData services:


  • My Accounts Service
  • My Sales Order Service

 

These two services share common entities:


  • Account
  • Address

 

In some implementations, I have seen the same code duplicated across different DPC_EXT classes for the same entity which doesn't lend itself to good re-use patterns although there certainly may be a use case where this is necessary.


Here is what I mean about acceleration, once I have the Account and Address entity implementation up and running, tested and stable I can re-use these entities across new services I'm putting together.


The initial build is obviously the longest but scaffolding up a new service with the same entities then becomes considerably faster.

 

 

blog_image.png

 

 

Data Provider Class ( DPC_EXT )


To facilitate this pattern, we need to make some changes in our DPC_EXT. This allows us to access instantiated concrete classes at runtime.

 

First we need an attribute on our DPC_EXT class that holds the instances of each entity implementation:



blog_image.png

 

 

The structure of the table is:

 

 

blog_image.png

 

 

Now to instantiate our entity implementations, during the constructor call in the DPC_EXT class we instantiate each entity and store the instance, class name and entity name:

 

 

blog_image.png

 

 

 

Now we need to call our entity concrete class implementation. Here we assume the service has been generated and you have re-defined the relevant method.

 

 

blog_image.png

 

 

 

ZCL_ODATA_RT


We've mentioned this class called ZCL_ODATA_RT.  The purpose of this class is to provide:



  • Common search capability based on dynamic SQL.  This means when I implement an entity for the first time I can re-use this search pattern that allows me to process complex searches that handles a range of other functions like paging.  In a nutshell we have implemented a re-usable search feature once across all our entity implementations that we can tailor for each concrete class. 

 

  • I can place framework specific functions such as eTag HASH calculations that will work across all of my entities



Overview of Entity Search


The first thing we probably want to do in the Fiori application is search for an entity.  I usually start by building out the generic search pattern in ZCL_ODATA_RT that follows this basic flow:



blog_image2.png




NB: I don't have to use this when setting up a new concrete class for the first time, I can redefine the GET_ENTITYSET method in the ZCL_ODATA_ACCOUNT and write other code to do the search for us.

 

Here is an overview of the logic of the GET_ENTITYSET method in ZCL_ODATA_RT:

 

1) Process paging, max hits and skip tokens.  This allows our dynamic SQL to retrieve our results based on certain filter parameters and then we have a generic paging pattern taken care for us. Think about the Master Object list in a Fiori app where you type in some search criteria and the OData call includes a "substring" filter.

 

blog_image.png

 

2) Generate a dynamic SQL statement.  This method contains the select, inner join, where statements.


blog_image.png


3) Apply additional filters.  Here I can read my entity filters passed by $filter and add additional criteria to our dynamic SQL

 

blog_image.png


4) Execute the dynamic SQL statement and page the results


blog_image.png

 

 

5) Enrich the data and return the result. This is where where you want to populate additional attributes of the entity that could not be retrieved during the dynamic SQL statement, thing such as texts or formatted names for example.

 

 

blog_image.png

 

 

Implementing the search in our concrete class

 

I now need to implement this in our concrete class.  When I have created our ZCL_ODATA_ACCOUNT class, I can then redefine the appropriate methods where I need to put my logic, this includes:


  • GENERATE_SELECT_FOR_ENTITYSET
  • ENRICH_WITH_USER_FILTER (not shown in our basic example below)
  • ENRICH_ENTITYSET_DATA

 

blog_image.png

 

 

Generate Select


In our generate select method, all we are doing is forming up the dynamic SQL, what attributes we want to select into our entity set.  We can also include joins here if we want to search across multiple tables.

blog_image.png

 

 

Enrich Entity Set Data


Before we pass the selected entity set records back to the odata framework we want to format and add additional things into the result.  Stuff like full name or texts.  In our example we've just formatted the full name of the business partner into the field FULL_NAME.


blog_image.png

 

 

We now have a concrete class implementation with an entity set search routine.



Implementing Other CRUD methods


We can then continue to implement the other CRUD functions by redefining the appropriate methods in our concrete class (ZCL_ODATA_ACCOUNT) and data provider class.


Let's do an GET_ENTITY example.  Here is the re-definition in the DPC_EXT class:

blog_image2.png

And let's put some logic in the ZCL_ODATA_ACCOUNT method GET_ENTITY:

blog_image.png

I won't go through POST, DELETE, UPDATE this should provide enough foundation for how the pattern works and encapsulates our business logic nicely into a concrete object.

 

 

Summary

 

In this part of the series we've demonstrated that it is possible to build a re-use pattern that encapsulates our entity implementations cleanly and also include a powerful search feature that we can consume on demand if required without having to re-write the same functions more than once.

 

I hope you have found this blog useful and see you next time where when we cover some performance considerations for your OData services and e-tag handling for data concurrency control.


Stay tuned for updates as I prepare a set of video walkthroughs to augment the content outlined in part 1 of this series and to show more complex search patterns.


Thanks for stopping by.

How $expand Influences the Importing Parameters of GET_ENTITYSET in SAP Gateway

$
0
0

Did you know that the method parameter IV_SOURCE_NAME of GET_ENTITYSET has different values depending on whether the service is triggered with or without $expand? This also applies to the parameter IT_NAVIGATION_PATH. I recently found out about this the hard way because not knowing this caused a bug in my code. I think it’s worth sharing my findings. Basically, you will see that using $expand fills the parameters mentioned above differently compared to directly triggering GET_ENTITYSETwithout $expand but still with Navigation Properties.

 

First of all, I’m using NW 7.4 SP12 together with SAP_GWFND SP12 (and some additional patches/notes).


image001.png



We’re going to use the GWSAMPLE_BASIC project/service that is shipped with your GW installation. You can simply go to the Service Builder (transaction code SEGW) and open the project /IWBEP/GWSAMPLE_BASIC. I like this project because I could see how SAP implements GW services – and I learned a lot from that in the past :-) Also, check Demo service ZGWSAMPLE_SRV | SCN by Andre Fischer which tells you a little more about the data model of the Gateway Sample Project.


image005.png



Now let’s first set a breakpoint in the method CONTACTSET_GET_ENTITYSET of the class /IWBEP/CL_GWSAMPLE_BAS_DPC_EXT. You can navigate there directly from SEGW (see screenshot above), or just use SE80.



image006.png


Now, after we have set the breakpoint, let’s try some example URLs and see what happens.



1. Without $expand: /sap/opu/odata/IWBEP/GWSAMPLE_BASIC/SalesOrderSet('0500000000')/ToBusinessPartner/ToContacts

 

As you can see this URL is using two Navigation Properties. First, we navigate to the BusinessPartner of a given SalesOrder, then to the BusinessPartner’s contacts. This will only return the contact data to the caller of the service. Calling this URL will hit the breakpoint we set above:

 

image009.png



While we are in the debugger inside CONTACTSET_GET_ENTITYSET let’s check the two mentioned parameters:


  • IV_SOURCE_NAME==> ”SalesOrder"
  • IT_NAVIGATION_PATH==> two entries, ToBusinessPArtner, ToContacts (see screenshot below)

 

image010.png



This basically tells us from the source "SalesOrder", we first navigated to the BusinessPartner and then to the contacts. The itab IT_NAVIGATION_PATH also contains information about the Target_Type (=Entity) and the corresponding namespace. So far so good. Now let’s assume we want a given SalesOrder and the contacts of its BusinessPartner in one request. We will achieve this using $expand.

 

 

2. With $expand: /sap/opu/odata/IWBEP/GWSAMPLE_BASIC/SalesOrderSet('0500000000')?$expand=ToBusinessPartner/ToContacts

 

Again, hitting this URL will hit our breakpoint. However, this time both IV_SOURCE_NAME and IT_NAVIGATION_PATH have different values (see screenshots below):

 

  • IV_SOURCE_NAME ==> ”BusinessPartner”
  • IT_NAVIGATION_PATH ==> 1 entry, ToContacts (for some reason the TARGET_TYPE_NAMESPACE is not filled)

 

image011.png

 

 

image012.png

 

This basically tells us from the source "BusinessPartner" we navigated to the contacts. However, this is not what I expected. I expected that using $expand in this scenario would be equal to calling our first URL from above in Step 1 (/sap/opu/odata/IWBEP/GWSAMPLE_BASIC/SalesOrderSet('0500000000')/ToBusinessPartner/ToContacts).

 

Instead, when using $expand in our scenario it’s basically equal to calling the URL /sap/opu/odata/IWBEP/GWSAMPLE_BASIC/BusinessPartnerSet('0100000000')/ToContacts, the explanation comes next.

 

 

3. Behind the scenes: /sap/opu/odata/IWBEP/GWSAMPLE_BASIC/BusinessPartnerSet('0100000000')/ToContacts

 

So, when using $expand, we now know what is actually called behind the scenes by the Gateway. Well, let’s prove this in the debugger by calling /sap/opu/odata/IWBEP/GWSAMPLE_BASIC/BusinessPartnerSet('0100000000')/ToContacts directly:



image013.png



image014.png



As you can see the result is equal to what we had in Step 2 – and that’s the prove:

 

  • IV_SOURCE_NAME ==> ”BusinessPartner”
  • IT_NAVIGATION_PATH==> 1 entry, ToContacts

 


However, this time for some reason the TARGET_TYPE_NAMESPACE is filled correctly – which I can’t explain :-)

I’m sure there is a good reason for the different values passed to the parameters – but I don’t know that reason :-)

Anyway… I’m aware of this now and I hope you are as well.

Make your SAP Gateway Work Smarter not Harder – Part 1.2 ) Search Patterns and Service inclusion

$
0
0

Introduction

 

 

Part 1 of this series can be found here if you have not seen it yet:

 

https://scn.sap.com/community/gateway/blog/2016/04/08/making-your-sap-gateway-work-smarter-not-harder-re-use-patternsa

 

In Part 1 we discussed development patterns in SAP Gateway and how we can achieve re-use and business logic encapsulation.

 

Two concepts we covered were a “search pattern” where we used Dynamic SQL to retrieve entity sets and a class hierarchy to encapsulate business logic and separate out functions on a module and gateway level.

 

In this blog I’d like to clarify and enhance the discussion by covering different options for Search and how to do Service Inclusion for re-use purposes.


 

 

Search Pattern and Class Hierarchy

 

In Part 1 we covered a possible class hierarchy where we could gain re-use and business logic encapsulation across our OData services and also included SAP module specific functions.

 

We also covered a generic search pattern that uses Dynamic SQL, that is ABAP code where you build up your own query and execute the SQL statements by manipulating “From” “Where” clauses.

 

The dynamic SQL doesn't sit well with a lot of people and here a few reasons why:

 

  • Code can be difficult to maintain, there are a lot of hard coded variables and requires a deep understanding of the SAP data model.


  • It is easy to go from simple use cases to complex ones and therefore create a larger technical debt than required.


  • There are obviously other choices and where a good "framework" is available there is certainly no rule that says don't use that instead.

 

 

Re-Jigging the Class Hierarchy

 

  • Removing the "Search Pattern" from ZCL_ODATA_RT.  This ensures that only SAP Gateway level functions are encapsulated here, this makes more sense to perform things like "E-Tag" handling rather than search.


  • Have a separate inheritance for the search pattern, in this case I've put a new class in the hierarchy called ZCL_ODATA_QRY_[search_function] where "[search_function]" is a framework specific search pattern. This doesn't have to be module specific, in systems like CRM I have different frameworks like BOL or Reporting Framework that I can re-use here across different modules like Service or Sales.

 

blog_image.png

 

 

Search Pattern - Example with Reporting Framework

 

This is an example I put together using Reporting Framework in CRM.  We created a new class "ZCL_ODATA_QRY_RF" which designates this class is coupled with the "Reporting Framework".  It still inherits from our ZCL_CRM_ODATA_RT class.


blog_image.png

 

We have a simple constructor that takes in a CRM BOL query and object type ( like a Business Activity BUS2000126 ) and instantiates a instance of of the IO_SEARCH class provided by SAP.


blog_image.png

 

And of course a "Search" method that takes in some query parameters, the IS_PAGING structure from our OData service and another flag that allows to return only the GUID's as a result rather than all the functional data.


blog_image.png

 

This is our search method implementation:

 

METHOD search.
 DATA: lt_return TYPE bapiret2_tab,
 ls_message_key TYPE scx_t100key,  lv_max_hits    TYPE i.
 FIELD-SYMBOLS: <result_tab> TYPE STANDARD TABLE.
 IF it_query_parameters IS INITIAL.
 RETURN.
 ENDIF.
 CALL METHOD gr_search->set_selection_parameters
 EXPORTING  iv_obj_il = gv_query  iv_obj_type = gv_object_type
 it_selection_parameters   = it_query_parameters
 IMPORTING  et_return = lt_return
 EXCEPTIONS  partner_fct_error         = 1  object_type_not_found     = 2
 multi_value_not_supported = 3
 OTHERS = 4.
 READ TABLE lt_return ASSIGNING FIELD-SYMBOL(<fs_message>) WITH KEY type = 'E'.
 IF sy-subrc = 0.
 ls_message_key-msgid = 'CLASS'.
 ls_message_key-msgno = 000.
 RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception EXPORTING textid = ls_message_key.
 ENDIF.
 IF iv_keys_only = abap_true.
 CALL METHOD gr_search->get_result_guids
 EXPORTING
 iv_max_hits  = lv_max_hits
 IMPORTING
 et_guid_list = rt_guids  et_return    = lt_return.
 READ TABLE lt_return ASSIGNING <fs_message> WITH KEY type = 'E'.
 IF sy-subrc = 0.
 ls_message_key-msgid = 'CLASS'.
 ls_message_key-msgno = 000.
 RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception EXPORTING textid = ls_message_key.
 ENDIF.
 ELSE.
 CALL METHOD gr_search->get_result_values
 EXPORTING
 iv_max_hits  = lv_max_hits
 IMPORTING
 et_results   = rt_results
 et_guid_list = rt_guids  et_return    = lt_return.
 READ TABLE lt_return ASSIGNING <fs_message> WITH KEY type = 'E'.
 IF sy-subrc = 0.
 ls_message_key-msgid = 'CLASS'.
 ls_message_key-msgno = 000.
 RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception EXPORTING textid = ls_message_key.
 ENDIF.
 ENDIF.
 **********************************************************************
 * Process Top / Skip tokens for paginglts
 **********************************************************************
 IF is_paging-skip > 0.
 DELETE rt_results FROM 1 TO is_paging-skip.
 DELETE rt_guids   FROM 1 TO is_paging-skip.
 ENDIF.
 IF is_paging-top > 0.
 DELETE rt_results FROM ( is_paging-top + 1 ).
 DELETE rt_guids   FROM ( is_paging-top + 1 ).
 ENDIF.
 ENDMETHOD.

 

So now when you want to execute the search in your concrete class, you can consume the SEARCH method in the inherited Search Framework plugin you've created:

 

METHOD /iwbep/if_mgw_appl_srv_runtime~get_entityset.
 DATA: lt_query_parameters TYPE genilt_selection_parameter_tab,  ls_query_parameter LIKE LINE OF lt_query_parameters,  lt_sort TYPE abap_sortorder_tab,  ls_sort TYPE abap_sortorder.
 FIELD-SYMBOLS: <fs_results> TYPE STANDARD TABLE.
 CREATE DATA er_entityset TYPE TABLE OF (gv_result_structure).
 ASSIGN er_entityset->* TO <fs_results>.
 **********************************************************************
 * Navigation Path from an Account
 **********************************************************************
 READ TABLE it_key_tab ASSIGNING FIELD-SYMBOL(<fs_key>) WITH KEY name = 'AccountId'.
 IF sy-subrc = 0.
 ls_query_parameter-attr_name = 'ACTIVITY_PARTNER'.
 ls_query_parameter-sign = 'I'.
 ls_query_parameter-option    = 'EQ'.
 MOVE <fs_key>-value TO ls_query_parameter-low.
 APPEND ls_query_parameter TO lt_query_parameters.
 ENDIF.
 **********************************************************************
 * Process Filters
 **********************************************************************
 LOOP AT it_filter_select_options ASSIGNING FIELD-SYMBOL(<fs_filter_select_option>).
 CASE <fs_filter_select_option>-property.
 WHEN 'ProcessType'.
 LOOP AT <fs_filter_select_option>-select_options ASSIGNING FIELD-SYMBOL(<fs_select_option>).
 MOVE-CORRESPONDING <fs_select_option> TO ls_query_parameter.  ls_query_parameter-attr_name = 'PROCESS_TYPE'.
 APPEND ls_query_parameter TO lt_query_parameters.
 ENDLOOP.
 WHEN OTHERS...
 .....<DO SOME MORE STUFF HERE TO HANDLE FILTERS>....
 ENDCASE.
 ENDLOOP.
 CALL METHOD search
 EXPORTING
 it_query_parameters = lt_query_parameters  iv_keys_only        = abap_false  is_paging           = is_paging
 IMPORTING  rt_results          = <fs_results>.
....COPY THE RESULTS TO THE EXPORT TABLE ETC....


Service Pattern Summary

 

Whilst this is a brief example, it shows the possibility of plug and play type frameworks for your OData services rather than tackling dynamic SQL that was included in the first part of this blog series.

 

If you've implemented a similar pattern I would love to hear from you with details about what you have put together..

 


Service Inclusion

 

Service Inclusion is the process of including another Service Model in your SAP Gateway Service Builder project, like this:

 

blog_image.png

 

 

blog_image.png

 

blog_image.png

 

Effectively, it allows you to access the Entities in service B directly from service A:

 

blog_image.png

 

This approach maximises the re-use of your services, not only will you get re-use and business logic encapsulation in the class hierarchy, your design time re-use is maximised as well.



Limitations / Gotchas

 

There are a couple of things to watch out for.

 

Referring to the diagram above, when you execute the URI for “/SALES_ORDER_SRV/Accounts(‘key’)/SalesOrders” the navigation path is not populated, a Filter parameter is passed to the SalesOrder GET_ENTITYSET where you now must filter the Sales Orders by the Account ID. 

 

What I mean by “limitation” is that usually you will be passed a navigation path ( IT_NAVIGATION_PATH) where you can assess where the navigation came from and what the keys were, in this use case you are missing the KEY_TAB values in the IT_NAVIGATION_PATH importing table in your GET_ENTITYSET method.

 

For this to work you must also set the referential constraint in the SEGW project and build your Associations as an external reference, like this:

 

blog_image.png

 

 

When the SAP Gateway framework attempts to assess which model reference your entity belongs to so it can execute a CRUD function, the underlying code loops over the collection of model references you have included ( in Service B ) and tries to find the first available model where your external navigation entity is located. 


In case you have implemented the same entity in multiple included services, SAP picks up the first available which can lead to surprises if you're wondering why your debug point is not being triggered during a GET_ENTITYSET method call in the wrong service



 

Service Inclusion Summary


If you haven't used this feature yet it provides a really great way to maximise re-use of your OData services, just a side note here; a really good use for this pattern is your common configuration entity model, things such as Country and State codes, Status Key Value pairs etc,


I have built a common service before that reads all of the configuration we use across different Fiori applications and are contained in one common service.


This way i simply "include" the common service so i don't have to keep implementing the same entity set or function import in different services.




Final Summary


I have put together this blog to try and clarify and provide a different perspective on Search capability within our OData services.  I know there are some of us out there that dislike the dynamic SQL scenario and for good reason.


My aim is to encourage some thought leadership in this space, so those customers tackling their OData service development can at least learn from our experience and embrace re-use patterns to really try and reduce TCO not to mention accelerate UX development in parallel.


As always, I'd love to hear from our community about other development patterns you've come up with so please share your thoughts and learnings, it's really important as our customers start to ramp up their OData and Fiori development.

Exploring Multiple Origin using System ID and Client

$
0
0

While working with Multi Origin in service URL we have to pass additional parameter SAP_Origin (i.e. nothing but your system alias pointing to corresponding ECC) in filter and Get entity operation.

 

When working on same scenarios i found one interesting possibility of passing the System ID (SID) and Client (of ECC) and fetch data from particular system.

 

What is Multi Origin?

 

Multiple origin is used to fetch data from different back-end systems, collect them in one single service and updating different back-end systems using the same user.

 

Why System ID and Client?

 

  • When creating OData requests you might not have information on any SAP NetWeaver Gateway system alias.
  • You might wish to refrain from exposing the system name of your SAP NetWeaver Gateway system in the URL of your service for security reasons. In this case, instead of the system name you can also use the system ID (SID) together with the corresponding client.

 

Pre-Requisite :

 

  • Gateway system is connected to all back end system
  • System alias is available for all back end system
  • GW Project is created in all the back end system
  • Add all system alias in T-code /n/IWFND/MAINT_SERVICE for the ZPROJECT_SRV in GW system
  • Using the URL sap/opu/odata/sap/ZPROJECT_SRV;mo/$metadata expected output is coming.


Alias eg.

FIORI_ECC1 : Backend System Alias 1 (SID - ABC, Client -100)

FIORI_ECC2 : Backend System Alias 2 (SID - XYZ, Client -100)



How to Use System ID and Client in URL ?


  • In Gateway system Open SAP Reference IMGin transaction SPROand navigate to SAP NetWeaver SAP Gateway OData Channel Configuration Connection Setting SAP Gateway to SAP System Manage SAP System Aliases

 

SPRO.PNG

 

  • Check for System Alias FIORI_ECC1 and FIORI_ECC2 in list.
  • Maintain SID and Client against System Alias


Manage SAP System.PNG

Now we are all set to test the scenario of using SID and Client in Gateway Service URl



Syntax for using SID and Client:

/sap/opu/odata/sap/ZPROJECT_SRV;o=sid(SID.Client)/EnitySet

In our case it will be:- /sap/opu/odata/sap/ZPROJECT_SRV;o=sid(ABC.100)/EnitySet

See the result which refrains output results  only from system ABC-100.


GW Client.PNG



Syntax for using System Alias:

/sap/opu/odata/sap/ZPROJECT_SRV;o=SystemAlias/EnitySet

or /sap/opu/odata/sap/ZPROJECT_SRV;mo/EnitySet?$filter=SAP_Origin eq 'SystemAlias'

In our case it will be:- /sap/opu/odata/sap/ZPROJECT_SRV;o=FIORI_ECC1/EnitySet

See the result which refrains output results  only from system alias FIORI_ECC1.


GW Client2.PNG


 

Similarly it works for create and deep create operation also.

Below I am showing an example working with create deep entity.


Create2.PNG


Create.PNG




The processing of request is as follows:

1.       The SAP NetWeaver Gateway system searches for all existing system aliases for the user and the specified service.

2.       The SAP NetWeaver Gateway system checks if one from above system aliases equals sid(ABC.100). If this is the case, this system will be used.

3.       If no such system exists underneath the specified service, then SAP NetWeaver Gateway checks whether one of the above system aliases has defined a system ID ABCand client 100.

4.       If this is the case, this system ID will be used. Otherwise an error message is displayed.



Hope this fills new developments. 

Why not build fewer, more useful OData services?

$
0
0

Do you ever have the feeling that you are missing something obvious?


The present

 

It seems to me that the current orthodoxy is that an OData service should be developed for each UI5 app.  In other words, each app should only have to call one service.  I think we should question whether that is the best approach.

 

Of course, a UI5 app can use many OData models, so long as each one has a unique name within the app.

 

In my opinion, when developing OData services (e.g. using Netweaver Gateway or HCI OData Provisioning), we should think of the big picture.  We shouldn't be too focused on the bespoke Fiori-style app we happen to be developing that day.  In a few years time we may have a large number of Fiori apps, both standard and bespoke.  There may be many other consumers of our OData services both internal (e.g. our own company website or intranet) and external (e.g. customer or supplier systems).

 

Why not take an 'API' approach, and think of our OData services as a way of interacting with the entities in our back end system?  Why not organise the services in such a way as to make it easy to navigate for any UI developer working with any technology? For example we could have a service for customers, one for inventory and one for employees. It seems to me that this would be much more in line with the RESTful architecture.  Just because we are using an SAP technology, such as Gateway, to deliver our services, it doesn't mean we should only consider SAP UI-technologies as consumers.  A big plus of the modern web-architecture is that the UI-layer is completely de-coupled from the data-provider and I think we should take advantage of that.

 

The future

 

If we (SAP and customers) carry on developing new services at a rapid rate, within a few years I fear we will have a large number of overlapping services.  It will be so hard to find one to use that developers will simply create another brand new service rather than trying to sort through that long list.  There will be much duplication of logic.

 

Each published service represents a responsibility (does it work as it should?) and a vulnerability (could it facilitate malicious activity?).  This isn't new (the same can be said for a remote-enabled function module) but surely a very large number of services makes it harder to manage these risks.

 

Pros & Cons

 

This is my take on the pros and cons of the one-service-per app model:

 

  • Robust, as development of a service for app #2 does not affect app #1.  This helps us get an app live very quickly, and may fit in better with an agile methodology(?).  This appeals to those who found the ESOA (Enterprise Service-Orientated Architecture) approach difficult to manage in practice
  • Re-usability can be introduced via 'Concrete classes', as described by Leigh Mason hereMaking your SAP Gateway work smarter not harderand also Service Inclusion
  • Data provider classes are quite small and manageable as there are only a few entities in each service
  • The service can be optimised for the app.  However, this can probably be achieved in a generic service by using features such as $select to specify the fields required.  Also, there is nothing to say that the 'customer' service must only have one, generic 'customer' entity
  • An external 'API' productcould perhaps be used to unify and present the services provided by Gateway (and other OData providers too)
  • Will lead in time to a large number of overlapping services.  It will be hard for a UI-developer to find what they need
  • Likely there will be a lot of duplication of logic (across services), leading to greater effort and reduced maintainability.  How many times will an employee entity be required, for example, in order to provide employee names?
  • Services are designed for individual apps on one particular platform (UI5/Fiori) and might not be suitable for future apps or other UI platforms

 

What do you think?  What do you do?

 

So, is there an obvious point that I am missing?  Are there advantages of the one-service-per-app approach that I have missed?  Am I wrong to call one-service-per-app the orthodoxy?

 

What is the strategy in your organisation (or at your clients) for OData services? I look forward to your comments.


ODATA SERVICE FOR PURCHASE REQUISITION CREATION

$
0
0

step1) Open TCode SEGW and create a project as shown in below screen shot.

1.png

Provide the following details


2.png

Then the components like

  1. 1. Data Model
  2. 2. Service Implementation
  3. 3. Runtime Artifacts
  4. 4. Service Maintenance

Gets displayed automatically.


step2. Create an entity type as follows

4.png

Provide as following.


5.png

6.png

Click on properties as shown below.

7.png

 

Add the following values for header as shown below

9.png

Same way create entity type PR_Item for the item also and give the following values

10.png

step3. Create an entityset as shown below.

11.png

Give the following details

12.png

Then Header Entityset is created.

13.png

     Same way create for Item Entityset is created.

14.png

step 4. Create a association as shown below.

15.png


16.png

17.png

18.png

19.png

And association set is automatically created.

step 5. Now Navigation is automatically created.

20.png

step 6.After completion of data model in Odata service in Service Implementation is filled automatically as shown in below screen shot.

21.png

step 7.Now we need to generate runtime artifacts ,for that you need to select Runtime Artifacts and click on

 

22.png

 

Click OK and save it.

24.png

We get the following in Runtime Artifacts .

25.png

step 8. We need write in ZCL_Z_PURCHASE_REQUISI_DPC_EXT so double click on it .

 

27.png

step 9 A.Then we need to right click on the methods and redefine required methods in following process.

28.png

And write following code  to get entity .


29.png

Code for Get Entity

 

 

 

 

 

method PRHEADERCOLLECTI_GET_ENTITY.

 

DATA: LS_KEY_TAB LIKE LINE OF IT_KEY_TAB.

 

     READ TABLE it_key_tab INTO ls_key_tab WITH KEY name ='PRNumber'.

 

ER_ENTITY-prnumber = LS_KEY_TAB-VALUE.

*    lv_pR_item = ls_key_tab-value.

**TRY.

*CALL METHOD SUPER->PRHEADERCOLLECTI_GET_ENTITY

*  EXPORTING

*    IV_ENTITY_NAME          =

*    IV_ENTITY_SET_NAME      =

*    IV_SOURCE_NAME          =

*    IT_KEY_TAB              =

**    io_request_object       =

**    io_tech_request_context =

*    IT_NAVIGATION_PATH      =

**  IMPORTING

**    er_entity               =

**    es_response_context     =

*    .

** CATCH /iwbep/cx_mgw_busi_exception .

** CATCH /iwbep/cx_mgw_tech_exception .

**ENDTRY.

endmethod.

 

 

 

9 B. Likewise redefine other required methods PRITEMCOLLECTION_GET_ENTITYSET and deep insert  also in same way  .

 

 

Code for GET_ENTITYSET

*** inactive new ***

METHOD PRITEMCOLLECTION_GET_ENTITYSET.

DATA:        ls_key_tab TYPE /iwbep/s_mgw_name_value_pair,

            lv_pr_number TYPE BANFN,

            lv_pr_item TYPE BNFPO,

            lt_pr_items_bapi TYPE TABLE OF BAPIEBAN,

            ls_pr_item_bapi TYPE BAPIEBAN,

            IT_RETURN TYPE STANDARD TABLE OF BAPIRETURN.

TYPES:

BEGIN OF ts_pr_item,

     PRITEM type C length 5,

     PURGROUP type C length 3,

     MATERIAL type C length 18,

     SHORTTEXT type C length 40,

     PLANT type C length 4,

     MATERIALGROUP type C length 9,

     QUANTITY type P length 7 decimals 3,

     UNIT type C length 3,

     DOCUMENTTYPE type C length 4,

     DELIVERYDATE type TIMESTAMP,

     ITEMCATEGORY type C length 1,

     ACCTASSIGNCATEGORY type C length 1,

     PRNUMBER type C length 10,

END OF ts_pr_item.

*

DATA: es_entityset LIKE LINE OF ET_ENTITYSET.

*

READ TABLE it_key_tab INTO ls_key_tab WITH KEY name ='PRNumber'.

lv_pR_number = ls_key_tab-value.

*

READ TABLE it_key_tab INTO ls_key_tab WITH KEY name ='PRItem'.

lv_pR_item = ls_key_tab-value.

 

CALL FUNCTION 'BAPI_REQUISITION_GETDETAIL'

EXPORTING

number =  lv_pr_number

tables

requisition_items =   lt_pr_items_bapi

RETURN =   IT_RETURN

          .

*DELETE lt_pr_items_bapi WHERE preq_item NE lv_pr_item.

*

READ TABLE lt_pr_items_bapi INTO ls_pr_item_bapi INDEX 1.

*

LOOP AT lt_pr_items_bapi INTO ls_pr_item_bapi.

*

      es_entityset-PRITEM = ls_pr_item_bapi-PReq_ITEM.

      es_entityset-PURGROUP = ls_pr_item_bapi-PUR_GROUP.

      es_entityset-material = ls_pr_item_bapi-material.

      es_entityset-SHORTTEXT = ls_pr_item_bapi-short_text.

      es_entityset-plant = ls_pr_item_bapi-plant.

      es_entityset-MATERIALGROUP = ls_pr_item_bapi-mat_grp.

      es_entityset-quantity = ls_pr_item_bapi-quantity .

      es_entityset-UNIT = ls_pr_item_bapi-unit .

      es_entityset-DOCUMENTTYPE = ls_pr_item_bapi-doc_type .

      es_entityset-ITEMCATEGORY = ls_pr_item_bapi-item_cat .

      es_entityset-ACCTASSIGNCATEGORY = ls_pr_item_bapi-acctasscat .

      es_entityset-PRNUMBER = ls_pr_item_bapi-preq_no .

      es_entityset-DeliveryDate = ls_pr_item_bapi-deliv_date .

 

      APPEND es_entityset TO et_entityset.

      CLEAR: es_entityset.

*

ENDLOOP.

  1. ENDMETHOD.

 

 

CODE FOR CREATE_DEEP_ENTITY

 

method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_DEEP_ENTITY.

**TRY.

*CALL METHOD SUPER->/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_DEEP_ENTITY

*  EXPORTING

**    iv_entity_name          =

**    iv_entity_set_name      =

**    iv_source_name          =

*    IO_DATA_PROVIDER        =

**    it_key_tab              =

**    it_navigation_path      =

*    IO_EXPAND               =

**    io_tech_request_context =

**  IMPORTING

**    er_deep_entity          =

*    .

** CATCH /iwbep/cx_mgw_busi_exception .

** CATCH /iwbep/cx_mgw_tech_exception .

**ENDTRY.

 

     DATA: lv_new_pr_no TYPE BAPIEBANC-PREQ_NO.

*             ls_new_pr_header TYPE BAPIMEREQHEADER.

 

DATA: ls_bapi_item TYPE bapiebanc,

          lt_bapi_item TYPE TABLE OF bapiebanc,

          lt_return TYPE TABLE OF bapiret2.

 

TYPES: ty_t_pr_items TYPE TABLE OF zcl_z_purchase_requisi_mpc=>ts_pr_item WITH DEFAULT KEY.

 

TYPES: BEGIN OF ts_pr_items.

            INCLUDE TYPE zcl_z_purchase_requisi_mpc=>ts_pr_header.

TYPES: PrItemCollection TYPE ty_t_pr_items,

           END OF ts_pr_items.

 

DATA: lt_items TYPE zcl_z_purchase_requisi_mpc=>tt_pr_header,

          ls_item  TYPE zcl_z_purchase_requisi_mpc=>ts_pr_item,

          lt1_items type ty_t_pr_items,

          ls_pritems TYPE ts_pr_items.

 

DATA: ls_data TYPE ts_pr_items.

 

CALL METHOD io_data_provider->read_entry_data( IMPORTING es_data = ls_data ).

*    ls_item-PRItemCollection  = ls_data-PrItemCollection.

lt1_items  = ls_data-PrItemCollection.

*append ls_item to it_items.

*clear ls_item.

 

 

*    LOOP AT lt_items INTO ls_item.

LOOP AT lt1_items INTO ls_item.

 

      ls_bapi_item-material = ls_item-material.

      ls_bapi_item-plant = ls_item-plant.

      ls_bapi_item-quantity = ls_item-quantity.

      ls_bapi_item-doc_type = ls_item-DocumentType.

      ls_bapi_item-DELIv_DATE = ls_item-DeliveryDate.

      ls_bapi_item-PUR_GROUP = ls_item-PURGROUP.

      ls_bapi_item-PREQ_ITEM = ls_item-PRITEM.

      ls_bapi_item-SHORT_TEXT = ls_item-SHORTTEXT.

      ls_bapi_item-MAT_GRP = ls_item-MATERIALGROUP.

      ls_bapi_item-UNIT = ls_item-UNIT.

      ls_bapi_item-ITEM_CAT = ls_item-ITEMCATEGORY.

      ls_bapi_item-ACCTASSCAT = ls_item-ACCTASSIGNCATEGORY.

      ls_bapi_item-PREQ_NO = ls_item-PRNUMBER.

*      ls_itemx-po_item = ls_item-item.

      APPEND ls_bapi_item TO lt_bapi_item.

*      APPEND ls_itemx TO lt_itemx.

      CLEAR ls_item.

ENDLOOP.

 

 

CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'

EXPORTING

INPUT         = lv_new_pr_no

IMPORTING

OUTPUT        = lv_new_pr_no

          .

CALL FUNCTION 'BAPI_REQUISITION_CREATE'

* EXPORTING

* SKIP_ITEMS_WITH_ERROR =

* AUTOMATIC_SOURCE = 'X'

IMPORTING

NUMBER = lv_new_pr_no

TABLES

requisition_items = lt_bapi_item

RETURN = lt_return

      .

 

CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'

      EXPORTING

        wait = 'X'.

*    MOVE-CORRESPONDING ls_headerdata TO ls_pritems.

ls_pritems-prnumber = lv_new_pr_no.

 

copy_data_to_ref(

      EXPORTING

        is_data = ls_pritems

      CHANGING

        cr_data = er_deep_entity ).

endmethod.

 

step10: Now Service Maintenance is automatically created but we need to register the service. So select the system i.e. EC7 and click on register.


30.png

Give the system Alias LOCAL_GW and click OK. Then Maintain The register

step 11.Test the service

 

Provide the following query

/sap/opu/odata/SAP/Z_PURCHASE_REQUISITION_TEST_SRV/PRHeaderCollection('0010003245')?$expand=PRItemcollection

33.png

Click on Use as Request.

34.png

Then you will get the response as request on left side

For Purchase Requisition creation you need to remove the Purchase Requisition number from left side.

35.png

/sap/opu/odata/SAP/Z_PURCHASE_REQUISITION_TEST_SRV/PRHeaderCollection() in gateway client and click on post

Purchase Requisition is created ‘0010017270’ as shown in below screen shot.


36.png

Check in Table level entries in EBAN we can find the Purchase Requisition '0010017270'


Elementary load testing of SAP Gateway oData services using cURL

$
0
0

Introduction


Probably everyone understands the need to perform load testing of applications and services. Usually it comes down to how much time and money one can spend in doing that. This blog gives a quick and free approach. Although not very advanced, it can be used to simulate load easily.

Requirements

 

A fairly recent version of cURL is required. If you plan on load testing with HTTPS, your cURL needs to support HTTPS. The certificate of the accessed server needs to be trusted as well. With cuRL the latter can be a bit tricky depending on how cURL was compiled. In case cURL doesn’t have in-built support for certificates, you can retrieve the CAs from the cURL website and convert them to CRT format using the provided mk-ca-bundle. Name the output file curl-ca-bundle.crt and place in the cURL directory.

 

This blog was written while using Windows as a platform, it should be straight forward to map the used commands to your choice of Operating System, such as Linux.

Solution

 

First you need to solve how to get the CSRF token and use it for all POST requests. The solution is to invoke cURL with –i  to retrieve the header variables and –D and store them so that you can parse them, use

curl –s –i –H "Accept: application/json" -H "X-CSRF-Token: fetch" -D headers.txt -u user:password https://myurl/mylistservice

To parse the header variables use

findstr "x-csrf-token" headers.txt > token.txt

and

set /p TOKEN=<token.txt

to store the CSRF token in an environment variable called TOKEN. Now to use the CSRF token in POST requests, use –H “%TOKEN%” in addition to any other header variables you may want to set, e.g.

curl –s –H "Content-Type: application/json" -H "Accept: application/json" -H "%TOKEN%" –u user:password -X POST --data-binary @payload.txt https://myurl/mycreateservice

The payload (in JSON format) is stored in a text file called payload.txt.

CSRF token validation failed

 

If you followed instructions in this blog to the letter, you probably still couldn’t make it work. Any attempt to use POST would fail with a token validation error, even though you sent the CSRF token in the request. The most likely reason for this is that Gateway is generating a new token for each request, invalidating the previous one. The root cause is that Gateway doesn’t recognize the session. It’s not sufficient to pass the CSRF token together with Basic Authentication; you need to also pass the identifying session information. The session information is stored in Cookies. With cURL you’ll have to use –c parameter to store the sent Cookies and –b to send them back. In other words you would add –c cookies.txt –b cookies.txt to each cURL command. The commands used in our examples would become

curl –s –i –c cookies.txt –b cookies.txt –H "Accept: application/json" -H "X-CSRF-Token: fetch" -D headers.txt -u user:password https://myurl/mylistservice

curl –s –c cookies.txt –b cookies.txt –H "Content-Type: application/json" -H "Accept: application/json" -H "%TOKEN%" –u user:password -X POST --data-binary @payload.txt https://myurl/mycreateservice

Taking it up a notch

 

Now that you have your elementary script ready, you might ask yourself “how can I simulate load”, e.g. have multiple instances running. The quick solution is to run the script in as many directories as you want parallel instances. A more clever approach is to have cURL create and use files in one directory with a prefix/suffix tying it to a specific instance. I myself did the latter by using the parent process ID (of Command Prompt) as identifier, that way you can start as many scripts from the same directory as you want and as your systems can handle. To give you an idea how that would look, here is how the 2 commands in our example look in my script

curl -s -i -c _cookies_"%PPID%".txt -b _cookies_"%PPID%".txt -H "Accept: application/json" -H "X-CSRF-Token: fetch" -D _headers_"%PPID%".txt -u "%USR%":"%PWD%" https://myurl/mylistservice

curl -s -c _cookies_"%PPID%".txt -b _cookies_"%PPID%".txt -H "Content-Type: application/json" -H "Accept: application/json" -H "%TOKEN%" -u "%USR%":"%PWD%" -X POST --data-binary @payload.txt https://myurl/createservice

PPID environment variable stores the process ID of the parent process. Obviously user and password are stored in environment variables USR and PWD defined in the script. To use multiple users, you could either use a rotating (or random) list or use the multiple directory approach.

Other tricks

 

If you want that your script waits between individual commands (or loop iterations), you can use

SET /A SLEEP=%RANDOM% * 10 / 32768 + 5

timeout /t %SLEEP% /nobreak

to set wait time of 5-15 seconds. If you plan to implement the parent process ID approach you’ll soon find out that it’s surprisingly difficult to retrieve the process ID of the parent process, in Windows that is. I ended up writing a C# program and calling it from the script.

Conclusion

 

While the approach discussed in this blog is elementary, it does the job. While commercial alternatives provide more advanced and realistic load testing they usually come with a significant price tag, especially if you need to simulate tens, hundreds or even thousands of clients.

How to apply range table in integration between Gateway and Hana View

$
0
0

Issue:

In integration between GW and hana view, hana view will provide input parameter as filter for one field, normally the input parameter accept one value. Issue is how to handle the filter has multiple values. For example, we need to count customer age distribution based on multiple branches customer belongs to.

 

Solution:

1. AMDP:

Define/implement method in AMDP class.

agedistribution

        IMPORTING

          VALUE(branch)              TYPE string

        EXPORTING

          VALUE(et_agedistribution)  TYPE tt_output_agedistribution,

 

et_agedistribution = SELECT "AGE", "AGERATE"

                         FROM "_SYS_BIC"."ZOUI5_CV_CUSTOMERAGE_SQL"

                         (PLACEHOLDER."$$ZBRANCH$$"=> :branch)

                         GROUP BY "AGE", "AGERATE", "ZCOUNT";

2. ABAP Class:

Combine filters and call AMDP method

DATA lt_partner TYPE RANGE OF bu_partner.
DATA ls_partner LIKE LINE OF lt_partner.
DATA: o_cond       TYPE REF TO cl_lib_seltab,
h_handle    
TYPE REF TO cl_abap_tabledescr,
branch_cond
TYPE string.

ls_partner-sign = 'I'.
ls_partner
-option = 'EQ'.
ls_partner
-low = '1000000001'.
APPEND ls_partner TO lt_partner.

ls_partner-sign = 'I'.
ls_partner
-option = 'EQ'.
ls_partner
-low = '1000000002'.
APPEND ls_partner TO lt_partner.

 

CALL METHOD cl_lib_seltab=>new
EXPORTING
it_sel
= lt_partner
RECEIVING
rr_ref
= o_cond.

CALL METHOD o_cond->sql_where_condition
EXPORTING
iv_field
= 'BRANCH'
RECEIVING
rv_cond 
= comm_bp_cond.
CONCATENATE '( ' branch_cond ' )' INTO branch_cond.

 

Branch_cond is like below:

(BRANCH = '1000000001' OR BRANCH = '1000000002')

 

Call AMDP Class:

               TRY.
           cl_admp_customer
=>agedistribution(
               
EXPORTING
                     branch      
= branch_cond
               
IMPORTING
                     et_agedistribution  
= lt_agedistribution
          
).
          
CATCH cx_amdp_execution_failed INTO DATA(lxage).
       
ENDTRY.

 

3. Stored Procedure:

Update stored procedure of ‘ZOUI5_CV_CUSTOMERAGE_SQL’ to adopt filter

var_filter =

apply_filter("_SYS_BIC"."ZOUI5_CV_CUSTOMER",:ZBRANCH)

;

 

var_int =

  select distinct

    BRANCH,

    CUSTOMER,

    AGE

  from

:var_filter;

 

Calculate Age distribution based on var_int.

Output is "AGE", "AGERATE"

OData service development with SAP Gateway - code-based service development - Part I

$
0
0

Introduction

 

In this blog I would like to show the basics of OData service development with SAP Gateway when using code based service implementation as it is shown in the upcoming SAP CodeJam events about OData service development with SAP Gateway.


Though the recommended approach for OData service development in the most recent SAP NetWeaver releases is to use CDS views there are still a number of use cases where code based service implementation is a valid option.

  1. Your SAP backend system is based on a SAP NetWeaver release 7.31 or earlier
  2. Your system is based on SAP NetWeaver 7.40 or later but the business logic you want to re-use has been implemented in ABAP code
  3. It is not possible to implement your business logic in CDS views

 

As an example we will use a simple OData model based that consist out of SalesOrders and SalesOrderItems with the option to navigate from a SalesOrder to the correponding line items.

 

 

Prequisites

 

The examples shown in this blog are based on the latest SAP NetWeaver release 750so that we can compare the different implementation approaches

 

 

Creating a basic OData service

 

We will perform the following steps:

 

  • Use the SAP Gateway Service Builder to create a new project
  • Import a DDIC structures for SalesOrder to create the data model
  • Generate, register and test the OData service using the Gateway Client
  • Perform a first implementation of the GET_ENTITYSET method

 

Create a new Service Builder project

 

  • Start the Gateway Service Builder by running transaction SEGW.

    image010.png

  • Click on the Create Project button
    image011.png
  • Provide the following information:

     

    Project: ZE2E100_XX

    Description: ZE2E100_XX

    Service Package: $TMP

     

    Note: Replace XX with your session-id / group number.

     

    image012.png

     

     

     

    • Press Continue
    • Press Save

    Import a DDIC structures for SalesOrder


    • Right-click on Data Model and select Import --> DDIC Structure.


    image013.png

    • In the first step of the wizard provide:

      In the field Name, enter SalesOrder
      In the field ABAP Structure, enter SEPM_ISOE.
      Click
      Next.

      image014.png

    • In the second step of the wizard provide:

      Select the checkbox for SEPM_ISOE.
      Deselect the checkbox for MANDT,
      Click Next.

      image015.png

    • In the third screen of the wizard

      Select the checkbox Is Key for the field SALESORDER.
      Click Finish.
      image016.png
    • Expand Folder Properties and examine the entity SalesOrder and the entity set SalesOrderSet.

      (For example the property names, the Edm Core Type values and the ABAP field names)
      image017.png
    • Press Save
    • Press the Check Project Consistency button.
    • Verify that no errors were found.
    • Press the Generate Runtime Objectsimage018.pngbutton.

      Note: Using the Generate Runtime Objects button automatically saves the project.

    • Leave all values as defaulted and press Enter.

    image019.png

    • Choose Local Object in the Create Object Directory Entry popup.
    • Verify that the generation was successful.

    image021.png


    Now you have created an (empty) service implementation in the SAP backend.

     

     

    Register and Test the OData service using the Gateway client

     

    • Expand the node Service Maintenance and right-click on GW_HUB and select Register.

    image022.png

    • In the Add Service popup leave all values as defaulted and press the Local Object button to assign the artifacts to the $tmp package. Then press Enter to continue

    image023.png

    • Double-click on the GW_HUB entry under Service Maintenance. Verify that the registration status on the right-hand side is showing a green traffic light.

    image024.png

    • In the navigation tree right-click on GW_HUB and select SAP Gateway Client.

      Alternatively click on the SAP Gateway Client button in the detail section.
      image025.png
    • Confirm the warning popup that warns you that you will be redirected to the selected system. Select Yes.
    • This opens up the SAP Gateway Client in a new screen. The URI of the service document is already defaulted.
      Press the Execute button.

    image027.png

    • As a result you get the service document of your OData service in the HTTP response window

    image028.png

    • Press the Button “Entity Sets” and select SalesOrderSet.

    image029.png

    • After pressing Execute button which executes the following URI

      /sap/opu/odata/SAP/ZE2E100_XX_SRV/SalesOrderSet

      you see an error message that indicates that the method SALESORDERSET_GET_ENTITYSET has not yet been implemented.

    image030.png



    Provision the GET_ENTITYSET method of the service using ABAP code

     

    • Open the Service Builder Project again (if you have closed it)
    • Expand the node Service Implementation and expand SalesOrderSet.
      Now right-click on GetEntitySet(Query) and choose
      Go to ABAP Workbench.

    image031.png

    • Confirm the warning

      “Operation SALESORDERSET_GET_ENTITYSET has not yet been implemented”
    • Switch to edit mode, scroll down to the method SALESORDERSET_GET_ENTITYSET and make sure to select it.

      Click on the Redefine Method button.

    image033.png

    • Use Copy&Paste to copy the entire coding shown below into the salesorderset_get_entityset method. Please note: This is a new syntax for ABAP SQL.

    select * from sepm_i_salesorder_e into corresponding fields of table @et_entityset.
    image034.png

      • Info: The replaced coding selects data from the CDS view sepm_i_salesorder_e.

        The results are filled into the corresponding fields of the return structure et_entityset of the get-entityset method.
        This works out of the box since the structure SEPM_ISOE was used to create the entity type using DDIC import. This structure is the so called sqlViewName of the CDS view sepm_i_salesorder_e. The source code of the DDL source can be viewed using the report RUTDDLSSHOW.
    • Click on Activate.
    • Confirm the activation popup.
    • Navigate back to the Service Builder main screen using the green back image035.pngbutton multiple times.
    • In the navigation tree right-click on GW_HUB and select SAP Gateway Client.

      Alternatively click on the SAP Gateway Client button in the detail section.

    image036.png

    • This opens up the SAP Gateway Client in a new screen. The URI of the service document is already defaulted.
      Press the Button “Entity Sets” and select BusinessPartnerSet
      The request URI field will contain the following value:

      /sap/opu/odata/SAP/ZE2E100_<XX>_SRV/SalesOrderSet

     

             (Replace ‘<XX>’ by your group number.)

     

             After pressing Execute button you see a list of sales orders.

     

    image037.png

     

    • You can retrieve the number of business partners by adding “/$count” to the request URI

      /sap/opu/odata/SAP/ZE2E100_<XX>_SRV/SalesOrderSet/$count
      Replace ‘<XX>’ by your group number and press Execute


    image038.png


    Add support for $filter to your code

     

    • Open the Service Builder Project again
    • Expand the node Service Implementation and BusinessPartnerSet and choose the entry GetEntitySet (Query).
      Now right-click on GetEntitySet (Query) and choose
      Go to ABAP Workbench.

    image039.png

    • This time the ABAP editor will open the method salesorderset_get_entityset  immediately.
      Switch to the change mode and replace the code with the code shown below.
      The code retrieves the $filter statement as an osql statement for the where clause.
      The data is retrieved and inserted into the return table et_entityset.


    data: lv_osql_where_clause type string.
    lv_osql_where_clause
    = io_tech_request_context->get_osql_where_clause( ).
    select * from sepm_i_salesorder_e
    into corresponding fields of table @et_entityset
    where (lv_osql_where_clause
    ).


    image040.png

    • Click on Activate.
    • Navigate back to the Service Builder main screen using the back button
    • In the navigation tree right-click on GW_HUB and select SAP Gateway Client.

      Alternatively click on the SAP Gateway Client button in the detail section.
    • This opens up the SAP Gateway Client in a new screen. The URI of the service document is already defaulted.
    • Replace the URI with the following:

      /sap/opu/odata/SAP/ZE2E100_XX_SRV/SalesOrderSet?$filter=Grossamountintransaccurrency ge 100000&$select=Salesorder,Grossamountintransaccurrency,Transactioncurrency&$format=json

      Replace ‘<XX>’ by your group number and press Execute

      This will deliver a list of four sales orders whose gross amount exceeds 100.000 Euro and will only show the sales order number and the gross amount.

      500000005
      500000030
      500000034
      500000045

    image041.png


    Add support for additional query options to your code

     

     

    • Open the Service Builder Project again
    • Expand the node Service Implementation and right-click on SalesOrderSet and choose the entry GetEntitySet (Query).
      Now right-click on GetEntitySet (Query) and choose
      Go to ABAP Workbench.


    • This time the ABAP editor will open the method salesorderset_get_entityset immediately.
    • Switch to the edit mode.
      Replace the code with the code shown below.
      The code retrieves the values for $top and $skip and the $filter statement as an osql statement for the where clause.The data is retrieved and in the end it is checked whether $inlinecount is used (which is a default for SAPUI5)


     

        data: lv_osql_where_clause type string,
    lv_top              
    type i,
    lv_skip             
    type i,
    lv_max_index        
    type i,
    n                   
    type i.
    *- get number of records requested
    lv_top
    = io_tech_request_context->get_top( ).
    *- get number of lines that should be skipped
    lv_skip
    = io_tech_request_context->get_skip( ).
    *- value for maxrows must only be calculated if the request also contains a $top
    if lv_top is not initial.
    lv_max_index
    = lv_top + lv_skip.
    endif.
    lv_osql_where_clause
    = io_tech_request_context->get_osql_where_clause( ).

    select * from sepm_i_salesorder_e
    into corresponding fields of table @et_entityset
    up to @lv_max_index rows
    where (lv_osql_where_clause).
    *- skipping entries specified by $skip
    if lv_skip is not initial.
    delete et_entityset to lv_skip.
    endif.
    *-  Inlinecount - get the total numbers of entries that fit to the where clause
    if io_tech_request_context->has_inlinecount( ) = abap_true.
    select count(*from   sepm_i_salesorder_e where (lv_osql_where_clause) .
    es_response_context
    -inlinecount = sy-dbcnt.
    else.
    clear es_response_context-inlinecount.
    endif.

    • Click on Activate.
    • Navigate back to the Service Builder main screen using the back button  multiple times.
    • In the navigation tree right-click on GW_HUB and select SAP Gateway Client.

      Alternatively click on the SAP Gateway Client button in the detail section.
    • This opens up the SAP Gateway Client in a new screen. The URI of the service document is already defaulted.
    • Replace the URI with the following:

      /sap/opu/odata/SAP/ZE2E100_XX_SRV/SalesOrderSet?$filter=Grossamountintransaccurrency ge 100000&$select=Salesorder,Grossamountintransaccurrency,Transactioncurrency&$top=2&$skip=1&$inlinecount=allpages&$format=json

      Replace ‘<XX>’ by your group number and press Execute
      This will deliver a list of only 2 sales orders whose gross amount exceeds 100.000 EUR. The first sales order 500000005 is skipped and only the first 2 of the rest of the list (highlighted in bold) are shown.
      The inlinecount however shows that in total 40 sales orders would fit to the filter criteria.

      500000005
      500000030 <--
      500000034 <--
      500000045

      Please note:
      $skip, $top and $inlinecount are used for client side paging. SAPUI5 uses this to calculate how many pages one has to navigate through.


    image043.png



    What is now left is the implementation of the GET_ENTITY method of the entity set SalesOrderSet and the modelling and implementation of the navigation between sales order header and the line items.


    This will be described in the second part of this blog post OData service development with SAP Gateway - code-based service development - Part II because the editor refused to let me add any additional screen shots at this point .

    OData service development with SAP Gateway - code-based service development - Part II

    $
    0
    0

    Since the editor didn't let me enter additional screen shots I am continuing my last blog post OData service development with SAP Gateway - code-based service development - Part I in a new one:

     

    We will continue our service implementation by implementing

     

    1. the GET_ENTITY method for the SalesOrderSet entity set and
    2. by implementing navigation to the items of a sales order

     

    Provision the GET_ENTITY method of the service using ABAP code


    • Open the Service Builder Project again
    • Expand the node Service Implementation and SalesOrderSet and choose the entry
      GetEntity (Read).
      Now right-click on
      GetEntity (Read) and choose
      Go to ABAP Workbench.

    image044.png

    • Confirm the warning

      “Operation SALESORDERSET_GET_ENTITY has not yet been implemented”

     

    • Switch to edit mode, scroll down to the method SALESORDERSET_GET_ENTITY and make sure to select it.

      Click on the Redefine Method button.

      Please note that the method SALESORDERSET_GET_ENTITYSET has already been redefined and therefore appears in black color.

    image045.png

    • Use Cut&Paste to copy the entire coding into the ABAP editor.

      Replace ‘<XX>’ by your group number

      The code first calls the method io_tech_request_context->get_converted_keys.

      The retrieved key value is used to select a single entry which is stored in the return structure
      er_entityof the method.


    data
    : lt_keys type /iwbep/t_mgw_tech_pairs,
    ls_key       
    type /iwbep/s_mgw_tech_pair,
    ls_bp_key    
    type zcl_ze2e100_<xx>_mpc=>ts_salesorder-salesorder,
    ls_headerdata
    type zcl_ze2e100_<xx>_mpc=>ts_salesorder.
    call method io_tech_request_context->get_converted_keysimporting
    es_key_values
    = ls_headerdata.

    ls_bp_key
    = ls_headerdata-salesorder.
    select single *into corresponding fields of @er_entityfrom sepm_i_salesorder_ewhere salesorder = @ls_headerdata-salesorder.


    • Click on Activate
    • Confirm the Activation popup
    • Navigate back to the Service Builder main screen using the back button  multiple times.
    • In the navigation tree right-click on GW_HUB and select SAP Gateway Client.
    • Alternatively click on the SAP Gateway Client button in the detail section.Enter the following URI
      /sap/opu/odata/SAP/ZE2E100_<XX>_SRV/SalesOrderSet('500000000')
      Replace ‘<XX>’ by your group number and Execute.
      You will get the details of a single business partner as a response

     

    image046.png

     

    Add an additional entity set for Sales Order Items

    • Open the Service Builder Project again
    • We will now create a second entity type for sales order items and entity set.

      Right-click again on Data Model and select Import --> DDIC Structure.


    • In the first step of the wizard provide:

      In the field Name, enter SalesOrderItem.
      In the field ABAP Structure, enter SEPM_ISOIE.
      Click Next.

    image047.png

    • In the second step of the wizard provide:

      Select the checkbox for SEPM_ISOIE.
      Deselect the checkbox for MANDT,Click Next.

    image048.png

    • In the third screen of the wizard:
      Select the checkbox Is Key for the fields SALESORDER and SALESORDERITEM.
      Click Finish.

    image049.png

    • Press Save

    Add an association and navigation properties

    • Expand Data Model and Right-click on Association and select Create

    image050.png

    • In the first step of the wizard provide:

      Association Name
      Assoc_SalesOrder_SalesOrderItem


    Principal Entity

    Entity Type Name

    SalesOrder

    Cardinality

    1


    Leave the checkbox Create related Navigation Property checked


    Enter ToItems in the field Navigation Property


    Dependent Entity

    Entity Type Name

    SalesOrderItem

    Cardinality

    1..n

     

    Select the checkbox Create related Navigation Property checked

    Enter ToSalesOrder in the field Navigation Property

    image051.png

    • Click Next
    • In the second step of the wizard in the field Dependent Property, enter SalesOrder by using the value help.
      Click
      Next

    image052.png

    • In the third step of the wizard press Finish.
    • Press the Check Project Consistency button.
    • Verify that no errors were found.
    • Press Generate Runtime Objects

    Provision the GET_ENTITY_SET method of the entity set SalesOrderItemSet

     

    • Open the Service Builder Project again
    • Expand the node Service Implementation and SalesOrderItemSet and choose the entry GetEntitySet (Query).
      Now right-click on GetEntitySet (Query) and choose Go to ABAP Workbench.

    image057.png

    • Confirm the warning

      “Operation SALESORDERITEMSE_GET_ENTITYSET has not yet been implemented”
    • Switch to edit mode, scroll down to the method SALESORDERITEMSE_GET_ENTITYSET and make sure to select it.

      Click on the Redefine Method button.

    image059.png

    • Use Cut&Paste to copy the entire code shown below.


      Replace ‘<XX>’ by your group number


      The code first calls the method io_tech_request_context->get_navigation_path.

      If the entity set is accessed via the navigation property ‘TOITEMS’ the sales order id is retrieved from the URI.

      If the entity set is accessed directly the where clause is retrieved from io_tech_request_context.

      Please note that the methods SALESORDERSET_GET_ENTITY and SALESORDERSET_GET_ENTITYSET have already been redefined and therefore appear in black color.


    data: lt_nav_path   type /iwbep/t_mgw_tech_navi,

    ls_nav_path   type /iwbep/s_mgw_tech_navi,

    lt_keys       type /iwbep/t_mgw_tech_pairs,

    ls_key        type /iwbep/s_mgw_tech_pair,

    ls_so_key     type zcl_ze2e100_xx_mpc=>ts_salesorder-salesorder,

    ls_headerdata type zcl_ze2e100_xx_mpc=>ts_salesorder.


    data: lv_osql_where_clause type string.


    lt_nav_path
    = io_tech_request_context->get_navigation_path( ).
    read table lt_nav_path into ls_nav_path with key nav_prop = 'TOITEMS'.
    if sy-subrc = 0.
    call method io_tech_request_context->get_converted_source_keysimporting
    es_key_values
    = ls_headerdata.

    ls_so_key
    = ls_headerdata-salesorder.
    select * from sepm_i_salesorderitem_einto corresponding fields of table @et_entitysetwhere salesorder = @ls_so_key.
    else.

    lv_osql_where_clause
    = io_tech_request_context->get_osql_where_clause_convert( ).
    select * from sepm_i_salesorderitem_einto corresponding fields of table @et_entitysetwhere (lv_osql_where_clause).
    endif
    .

    • Click on Activate
    • Confirm the Activation popup
    • Navigate back to the Service Builder main screen using the back button  multiple times.
    • In the navigation tree right-click on GW_HUB and select SAP Gateway Client.

      Alternatively click on the SAP Gateway Client button in the detail section.


    • Enter the following URI

      /sap/opu/odata/SAP/ZE2E100_XX_SRV/SalesOrderSet('500000000')/ToItems

      Replace ‘<XX>’ by your group number and
      Execute.
      You will get the items of the sales order
      '500000000' as a response.


    • Enter the following URI

      /sap/opu/odata/SAP/ZE2E100_XX_SRV/SalesOrderItemSet?$filter=Salesorder eq '500000000'

      Replace ‘<XX>’ by your group number and Execute.

      Also here you will get the items of the sales order
      '500000000' as a response

    OData service development with SAP Gateway using CDS via Referenced Data Sources

    $
    0
    0

    Introduction

     

    In a previous blog OData service development with SAP Gateway - code-based service development - Part I I described how to implement as basic OData Service using code based implementation.

     

    Since the recommended development approach as of SAP NetWeaver 750 is to use CDS views I would like to show how a service having the same capabilities as the service in the blog mentioned above can be generated based on CDS views.

     

    It will turn out that from a development perspective in the ABAP stack this is much less effort if appropriate CDS views are in place and if your backend system is based on SAP NetWeaver 750.

     

    If however no appropriate CDS view is in place instead of having the effort of developing an OData service via code based implementation you would have the effort to develop the appropriate DDL source code.

     

     

    Generating an OData service via Referenced Data Source

     

    • We first have to start with creating a new Service Builder project calledZE2E100_<XX>_2 since the project in the previous blog mentioned above was calledZE2E100_<XX>

      Note:
      Replace <xx> with your group number
    • Right click on the folder Data Model.

      Choose Reference -->
      Modeled Data Source Reference from the context menu

    image082.png

    • The Reference Data Source Wizard opens.


      On the first screen choose:
      CDS Core Data Services for the field Modeled Data Source Type.
      SEPM_I_SALESORDER_E for the field Modeled Data Source Name

    rds01.jpg

    • In the second window of the wizard select the following associations’

      _CUSTOMER and _ITEM.

      Please note that the cds views SEPM_I_BUSINESSPATNER_E and SEPM_I_SALESORDERITEM_E are automatically selected as well.


      Press Finish


    rds02.jpg

    Please note that the CDS views SEPM_I_SALESORDER_E and SEPM_I_SALESORDERITEM_E are both marked as "Analytical". This will have a result in the format of the key values of the results as being shown later in this blog.


    • Press the Generate Runtime Objects button


    • In the Model and Service Definition screen leave the default values unchanged and press Continue.

    image086.png

    • In the Create Object Directory Entry dialogue press Local Object or enter $TMP.


    • Expand the folder Service Maintenance right click on the entry GW_HUB and choose Register.

    image088.png

    • In the Add Service dialogue enter $TMP for the package assignment or press Local Object.

    image089.png

    • Expand the folder Service Maintenance right click on the entry GW_HUB and choose SAP Gateway Client.

      Press <Execute>

    image090.png

    • Check the Service Document

      It shall contain three entity sets:
      1. SEPM_I_SalesOrder_E
      2. SEPM_I_SalesOrderItem_E
      3. SEPM_I_BusinessPartner_E

    rds04.jpg

    • Check the metadata document by selecting <Add URI option> and select $metadata

     

    Check the Metadata Document
    Please note that the entity type SEPM_I_SalesOrder_EType contains:

      • Two navigation properties to_Customer and to_Item
      • A property SalesOrder_Text that has been generated by the SADL framework based on the annotation @ObjectModel.text.association: '_Text'.

        Please note this property is annotated as sap:updatable=”false”;

     

    rds06.jpg

    • Now we can test the service and we will see that it supports various query options, $expand and selecting single entities out of the box.

      To do so execute the following URI’s in the SAP Gateway Client (transaction /n/IWFND/GW_CLIENT):
      • /sap/opu/odata/SAP/ZE2E100_XX_2_SRV/SEPM_I_SalesOrder_E?$filter=GrossAmountInTransacCurrency ge 100000&$select=SalesOrder,GrossAmountInTransacCurrency,TransactionCurrency&$format=json

     

      • $skip and $top together with $inlinecount work out of the box as well

        /sap/opu/odata/SAP/ZE2E100_XX_2_SRV/SEPM_I_SalesOrder_E?$filter=GrossAmountInTransacCurrency ge 100000&$select=SalesOrder,GrossAmountInTransacCurrency,TransactionCurrency&$top=2&$skip=1&$inlinecount=allpages&$format=json

        Please note that via &$inlinecount=allpages we retrieve the number of entries that would be returned without using $skip and $top

    rds09.jpg

      • Read a single entity from the list of the sales order

        /sap/opu/odata/SAP/ZE2E100_XX_2_SRV/SEPM_I_SalesOrder_E('-.-.-.-.-.-.10.-.-.-.-.-.-._.0500000000')?$format=json

        Please note that the weird looking key stems from the fact that the CDS view is annotated as an analytical view.

      • Read the list of items of a single sales order via the navigation property to_Item

        /sap/opu/odata/SAP/ZE2E100_XX_2_SRV/SEPM_I_SalesOrder_E('-.-.-.-.-.-.10.-.-.-.-.-.-._.0500000000')/to_Item?$format=json

     

     

    How to implement updates in a service that has been generated using referenced data sources will be described in an upcoming blog ...

    OData service development with SAP Gateway using CDS via Referenced Data Sources - How to implement updates

    $
    0
    0

    Introduction

     

    The OData service that has been generated in the first part of this blog is read only.

     

    In the second part of the blog OData service development with SAP Gateway using CDS via Referenced Data Sources I would like to show how we can make the description of the sales order updatable.

     

    This will show

     

    1. how simple updates can be implemented and in particular
    2. how this can be done for Texts that are accessed by the SADL framework via a join and the annotation @ObjectModel.text.association: '_Text'.

     

    Implementation

     

    • Open the Service Builder project ZE2E100_<XX>_2 again that has been built based on the blog mentioned above.
    • Expand the folder Runtime artifacts and right-click on ZZCL_ZE2E100_XX_2_DPC_EXT and choose the entry Go To ABAP Workbench.

    image098.png

    • Switch to edit mode, scroll down to the method ZSEPM_C_SALESORD_UPDATE_ENTITY and make sure to select it and click on the Redefine Method button.

    rds_cud_01.jpg

    • Copy and Paste the coding into the Update method


      method zsepm_c_salesord_update_entity.

     

         data: lt_keys               type /iwbep/t_mgw_tech_pairs,

               ls_key                type /iwbep/s_mgw_tech_pair,

               ls_so_id              type bapi_epm_so_id,

               ls_headerdata_update  type bapi_epm_so_header,

               ls_headerdatax        type bapi_epm_so_headerx,

               ls_headerdata_key     type zcl_ze2e100_xx_2_mpc=>ts_zsepm_c_salesorder_tpltype,

               ls_headerdata_payload type zcl_ze2e100_xx_2_mpc=>ts_zsepm_c_salesorder_tpltype,

               lt_return             type table of bapiret2,

               ls_return             type          bapiret2,

               err_msg               type          string,

               ls_message            type          scx_t100key.

     

         call method io_tech_request_context->get_converted_keys

           importing

             es_key_values = ls_headerdata_key.

     

         io_data_provider->read_entry_data( importing es_data ls_headerdata_payload ).

     

         ls_so_id-so_id = ls_headerdata_key-salesorder.

     

         " Product header data (non-key) fields that can be updated

         " via the BAPI are marked with an 'X'

     

         ls_headerdatax-so_id = ls_headerdata_key-salesorder.

         ls_headerdatax-note = 'X'.

     

         " move content of the fields that should be

         " updated from payload to the corresponding

         " field of the BAPI

     

         move ls_headerdata_key-salesorder to ls_headerdata_update-so_id.

         move ls_headerdata_payload-t_salesorder  to ls_headerdata_update-note.

     

         call function 'BAPI_EPM_SO_CHANGE'

           exporting

             so_id         = ls_so_id         " EPM: SO Id

             soheaderdata  = ls_headerdata_update " EPM: so header data of BOR object

             soheaderdatax = ls_headerdatax

           tables

             return        = lt_return.     " Return Parameter

     

         if lt_return is not initial.

     

           loop at lt_return into ls_return.

     

             err_msg = ls_return-message .

     

           endloop.

     

           ls_message-msgid = 'SY'.

           ls_message-msgno = '002'.

           ls_message-attr1 = err_msg.

     

           raise exception type /iwbep/cx_mgw_busi_exception

             exporting

               textid = ls_message.

     

         endif.

     

     

       endmethod.

     


    Info: The replaced coding above retrieves the content of the properties of the incoming request.

    Since different DDIC structures are used by the entity type and the BAPI that is used to update the sales order the incoming fields are moved to the data structure used by the BAPI.


    • To make the SAP Web IDE CUD Master Detail Template aware that the property SalesOrder_Text is now updatatable we have to annotate the property using the annoation sap:updatable=true.

      In this special case this cannot be done in the CDS view. So we have to use the option to add additional metadata by implementing the DEFINE method in the model provider extension class.
    • Expand the folder Runtime artifacts and right-click on ZZCL_ZE2E100_XX_2_DPC_EXT and choose the entry Go To ABAP Workbench.
    • Copy and paste the following coding into the DEFINE method.

    method define.

     

         data:

           lo_entity_type type ref to /iwbep/if_mgw_odata_entity_typ,

           lo_property    type ref to /iwbep/if_mgw_odata_property.

     

         call method super->define( ).

         lo_entity_type = model->get_entity_type( iv_entity_name = 'Zsepm_C_Salesorder_TplType').

         lo_property = lo_entity_type->get_property( iv_property_name = 'SalesOrder_Text').

         lo_property->set_updatable( abap_true ).

     

    endmethod.

     

    • Click on Activate.
    • Confirm the activation popup.
    • Navigate back to the Service Builder by pressing the “Back-Button” several times
    • In the navigation tree right-click on GW_HUB and select SAP Gateway Client.

      Alternatively start the SAP Gateway Client in a separate window by starting transaction /n/IWFND/GW_CLIENT

      If we now test the update using the SAP Gateway Client this should work fine.


    • Enter the following URI

      /sap/opu/odata/SAP/ZE2E100_XX_2_SRV/Zsepm_C_Salesorder_Tpl('5000000<XX>')

      After pressing Execute button you see a single sales order.

      Replace ‘<XX>’ with your group name
    • Press the Use as Request button to create a proper http request body.
      Change the content of the field SalesOrder_Text for example to ‘Test Update Text’.
      Change the http method from GET to PUT.
      Press Execute

    rds_cud_03.jpg

    • As a result you get an empty http response with the return code 204.

    rds_cud_04.jpg

    • Now again perform a GET request to verify that the data has been changed
      Enter the following URI
      /sap/opu/odata/SAP/ZE2E100_XX_2_SRV/Zsepm_C_Salesorder_Tpl('5000000<XX>')
      After pressing Execute button you see a single sales order with the changed text.
      Replace ‘<XX>’ with your group name

    rds_cud_04a.jpg

     

    Testing with SAP Web IDE

     

    When testing with the CUD Master Detail Template in SAP Web IDE it turns out that the update of the field will not work.

     

    This is because to a small bug that is planned to be fixed with SAP NetWeaver 750 SP04.

     

    As a workaround we have to redefine the method /IWBEP/IF_MGW_CORE_SRV_RUNTIME~CHANGESET_BEGIN.

     

    After you have added the following code

     

      method /IWBEP/IF_MGW_CORE_SRV_RUNTIME~CHANGESET_BEGIN.

    cv_defer_mode
    = abap_false.

    endmethod.


    rds_cud_05.jpg

     

     

    The text will be updated as you can check with the SAP Gateway Client

     

    rds_cud_06.jpg


    SAP CodeJam

    $
    0
    0

    In this blog I am collecting information about what you can do in advance when attending a SAP CodeJam about SAP Gateway and provide links about SCN blogs that we will use in such an event.

     

    What to prepare in advance

     

    *Remember this is a "bring your own laptop" event**

    You have to bring your own laptop with you. On this you have to have installed SAPGUI to work with the SAP Gateway design time, the SAP Gateway Service Builder. In addition you need a browser to access the SAP Web IDE.

     

    Gateway System

    We will provide a SAP Gateway Sandbox system for the time of the event. This will however be dismantled afterwards. So if you want to work in a system that is available after the event we recommend to go for a SCN Trial Editions of SAP NetWeaver Application Server ABAP 7.4. More information how to get your hands on a trial version can be found here: http://www.sap.com/abaptrial

     

    SAPGUI

    In order to connect to the Gateway System and to develop your own services you have to have SAPGUI installed on your desktop.

    If not already installed you can get it here: http://www.sdn.sap.com/irj/sdn/index?rid=/webcontent/uuid/1024acfb-5b30-2e10-f2bd-ccce5d8692b1

     

    SAP Web IDE

     

    In order to generate a SAP UI5 application that can consume the OData service that you are going to build we will use SAP Web IDE.

    There is no need to install anything on your laptop since SAP Web IDE runs in the SAP HANA Cloud platform.

    The only thing that you have to do is to register for a free HCP developer account using your SCN credentials.


    This you can do here: SAP HANA Cloud Cockpit


    A file to import the destination of the ABAP demo system we use has been attached to this blog. You only have to replace the IP-Address that we will tell you when you attend.


    Get the ABAP Development Tools for Eclipse

    Install the latest version of the ABAP Development Tools for Eclipse from the update site SAP Development Tools for Eclipse. This tool is needed if you want to create your own CDS view.

     

    How To Guides

     

    OData service development with SAP Gateway - code-based service development - Part I

     

    OData service development with SAP Gateway - code-based service development - Part II

     

    OData service development with SAP Gateway using CDS via Referenced Data Sources


    OData service development with SAP Gateway using CDS via Referenced Data Sources - How to implement updates

    Closing session of Soft State OData service

    $
    0
    0

     

    Hello,

    I would like to share the idea how you can manage or kill the session of your Soft State OData Service.

    For more information regarding Soft State Support for OData Services look here: http://help.sap.com/saphelp_gateway20sp09/helpdata/en/f6/5f8e5318e83d27e10000000a44538d/content.htm

    and here:

    http://scn.sap.com/docs/DOC-58760.

    As discussed, you will probably implement Stateful or Soft State OData in the applications, where you can gain a lot from this. This can be any application, which is continuously working with considerable amount of data. Typical example would be taking an order with many items and complex pricing or very complex and flexible reports, which are working with the data stored in the memory. By default, your session will timeout according to the settings you set up for your service in the transaction SICF.

    Now it comes a tricky question, how big should this timeout be? 1 hour or maybe 1 second? You’llsay, depends on the application. Yes, true. But, isn’t it better to make it manageable?

    Imagine in your order taking application you have simply forgotten, or maybe it is just not possible, to release the memory after the order is finished. Your memory will be leaking, right? Even closing the browser will not help. You will see more and more pending sessions in SM04 (AL08) transaction, consuming more and more memory of your system.

    SM04.jpg

    Below I will describe one way how you can close the Soft State OData session programmatically.

    First, what you need to know that it is possible to kill this session right from transaction SM04. Therefore, we will simulate exactly this step.

    You can get the session information using CL_SERVER_INFO => GET_SESSION_LIST. After that, you will need to call the function TH_DELETE_USER to kill this session. Let’s to a simple function, where the input parameter would be a path to the OData service.

    functionzdmsh_delete_odata_session.
     
    *"----------------------------------------------------------------------
     
    *"*"Local Interface:
     
    *"  IMPORTING
     
    *"     VALUE(IV_PATH) TYPE  STRING
     
    *"----------------------------------------------------------------------
     
       
    include: tskhincl.
     
       
    data: server_info  type ref to cl_server_info.
     
       
    data(lv_path) = iv_path.
       
    translatelv_pathto upper case.
     
       
    try.
           
    createobject server_info.
     
           
    data(session_list) = server_info->get_session_list( with_application_info = 1
                                                                tenant
    = sy-mandt ).
     
           
    loop at session_list assigning field-symbol(<fs_session_info>)
             
    where user_name  = sy-uname
               
    and logon_type= 3
               
    and logon_sub_type= 4
               
    and act_program= 'SAPMHTTP'.
     
             
    translate<fs_session_info>-application_info to upper case.
     
             
    if<fs_session_info>-application_infocslv_path.
     
               
    call function 'TH_DELETE_USER'
                 
    exporting
                    user           
    = sy-uname
                   
    client          = sy-mandt
                    tid            
    = <fs_session_info>-logon_hdl
                    logon_id       
    = <fs_session_info>-logon_id
                 
    exceptions
                    authority_error
    = 1
                   
    others          = 2.
               
    ifsy-subrc<> 0.
                 
    continue.
               
    endif.
             
    endif.
           
    endloop.
     
         
    catchcx_root.
           
    exit.
       
    endtry.
     
     
    endfunction.

     

    Then you need to call this function somehow. In my case, the function TH_DELETE_USER does not work if I call it from the same session, which I am trying to kill. Don’t know why, but it was the case. Therefore, you need to call it from another session, which can be another OData service or simply a web-rfc function.

    I used the last option. For more information regarding web-rfc, see here: http://scn.sap.com/community/netweaver-as/blog/2012/08/07/webrfc--simply-calling-an-rfc-from-javascript

    So, the function looks very simple.

    functionzdmsh_delete_user_webrfc.
     
    *"----------------------------------------------------------------------
     
    *"*"Local Interface:
     
    *"  TABLES
     
    *"      QUERY_STRING STRUCTURE  W3QUERY
     
    *"      HTML STRUCTURE  W3HTML
     
    *"      MIME STRUCTURE  W3MIME
     
    *"  CHANGING
     
    *"     REFERENCE(CONTENT_TYPE) TYPE  W3PARAM-CONT_TYPE DEFAULT
     
    *"       'application/json'
     
    *"     REFERENCE(CONTENT_LENGTH) TYPE  W3PARAM-CONT_LEN
     
    *"     REFERENCE(RETURN_CODE) TYPE  W3PARAM-RET_CODE
     
    *"----------------------------------------------------------------------
     
       
    data: path type string.
       
    data: rctype numc5.
     
       
    sortquery_stringdescending.
       
    read table query_stringwith key name = '_OdataSrv'.
     
        path
    = query_string-value.
     
       
    call function 'ZDMSH_DELETE_ODATA_SESSION'
         
    exporting
            iv_path
    = path
         
    importing
            rc     
    = rc.
     
       
    data: htmldoclike line of html.
     
       
    concatenate'{"results": [ {"key": "path", "value": "' path '"},'
                                
    ' {"key": "error", "value": "' rc '"}]}' into htmldoc-line.
     
       
    inserthtmldocinto table html.
     
     
    endfunction.

     

    After that, you just need to call it via the URL: http://<server>:<port>//sap/bc/webrfc?_FUNCTION=<FUNC_NAME>&_OdataSrv=<SERVICE_PATH>

    At last, you need to create a JavaScript function and attach it to proper event (e.g. window.onbeforeunload / window.addEventListener) or a button. From there you can call the above URL, for instance as AJAX request.

    Hope it was useful.

    If you find any mistake or a bug, or have a better solution, do not hesitate to comment it cout.

    BR, Dima

     

     

    Uninstallation of SAP Gateway add-ons IW_FNDGC, IW_GIL, IW_SPI, IW_SCS, IW_CNT 200 and IW_CBS 200

    $
    0
    0

    Introduction

     

    SAP Gateway consist out of several add-ons. Some of them are mandatory while others are only optional and some are even legacy. A complete list of SAP Gateway add-ons can be found in the SAP Online Help Installing SAP Gateway Components - SAP Gateway - SAP Library

     

    So far all of the above mentioned add-ons have to be maintained and upgraded in a customer system landscape once you have installed them because it was not possible to uninstall SAP Gateway add-ons in the past. In the "worst case" you could have up to ten SAP Gateway add-ons installed in your SAP Gateway Hub and SAP Business Suite Backend

     

    In order to offer the option to simplify your SAP Gateway landscape and because several of the SAP Gateway add-ons will not be supported by S/4 HANA you have now the option to uninstall the following SAP Gateway add-ons:

     

    • IW_SCS 200, IW_CNT 200 and IW_CBS 200
    • IW_GIL 100 and IW_SPI 100
    • IW_FNDGC 100

     

    In the following two pictures these uninstallable add-ons have been marked with red.


    Slide1.PNG


    The add-ons GW_CORE, IW_FND, IW_BEP and IW_HDB are not uninstallable since their content became part of the software component SAP_GWFND which is part of the SAP Basis as of SAP NetWeaver 740.


    If we have a look at the add-on / software component structure of SAP Gateway as of SAP NetWeaver 740 it turns out that the total number of add-ons / software components that are mandatory and thus not uninstallable has been reduced to two add-ons while up to six add-ons are now uninstallable.

     

    Please note that IW_PGW is used for SAP Fiori applications such as the MyInbox and that it is planned to include the coding into the software component SAP_GWFND as well.

     

    Slide2.PNG

     

    As mentioned above there are two reasons why you may want to remove an SAP Gateway add-on:

     

    1. Remove add-ons that are not needed

     

    As said, some of the add-ons only contain legacy functionality such as the screen scraping generator (IW_SCS) as well as (outdated) content which is based on the so called generic channel (IW_CNT and IW_CBS). Therefore you can uninstall these add-ons unless you are using services that are based on these legacy components. See SAP Note 2312680 for more details.

     

    The add-on IW_FNDGC is only needed for customers using the above mentioned (outdated) services based on the Generic Channel when they upgrade their SAP Gateway Hub to SAP NetWeaver 740. This is because the add-ons IW_CNT and IW_CBS do depend on components that are shipped with the add-on IW_FNDGC. Therefore you can uninstall this add-on as well once you have uninstalled the add-ons IW_CNT and IW_CBS mentioned above.


    This leaves us to the add-ons IW_GIL and IW_SPI. These add-ons were developed to allow customers to generate OData services using SEGW in a process called redefinition based on Service Provider Interface objects or GenIL objects. Customers that have installed these add-ons but are not using any service that has been generated based on these add-ons can benefit from the uninstallation option as well.

     

    2. Transition to S/4 HANA

     

    With the transition to S/4 HANA it was decided to not support all add-ons of SAP Gateway since not all of them are used within S/4 HANA and are thus not needed to build OData in S/4 HANA. As a result it was necessary to make these add-ons uninstallable so that they can be uninstalled before starting a transition of a customer SAP Business Suite System to S/4 HANA.

     

    How to remove an SAP Gateway add-on?

     

    1. Import SAINT update

     

    As described in SAP Note 2011192 - Uninstalling ABAP add-ons as of Version 0053 of the SAP Add-On Installation Tool, not only can you install ABAP add-ons, but you can also uninstall them again in certain circumstances.


    As of version 0061 it is now possible to uninstall the above mentioned SAP Gateway add-ons using SAINT.

     

    2. Import Attribute Change Packages

     

    Since the service packs in your system are not yet marked as uninstallable you have to import so called Attribute Change Packages that will change the uninstallable attribute of your service pack accordingly. How to find the ACPs is described in SAP Note 1119856 - Description, tips and tricks for Attribute Change Packages

     

    The names of the ACPs you might be looking for are the following

     

    IW_SPI====100

    IW_GIL====100 

    IW_SCS====200

    IW_CNT====200

    IW_CBS====200

    IW_FNDGC==100

     

    You can search for them via the new launchpad UI from SAP quite easily if you use the following URL

     

    https://launchpad.support.sap.com/#/softwarecenter/search/IW_SPI====200

     

    Search ACP for IW_SPI.png

     

    After you have updated SAINT to at least version 0061 you can upload the ACP into SAINT directly from your front end. As described in the note above you do not have to import them. Instead, they already take effect when you upload them into the system when you use the function "Load From Front End") so that they show up in the tab "Deinstallable components".

     

    The following screen shot shows SAINT after the above mentioned ACP IW_SPI====200 has been uploaded.

     

    After upload of ACP IW_SPI.png

     

    More information

     

    You will find more detailed information about the uninstallation procedure and the technical prerequisites in the following SAP Notes:

     

    SAP Gateway 2.0

     

     

    SAP NetWeaver 7.40

     

    Using SEGW and ABAP in Eclipse

    $
    0
    0

    In one of my last blogs about code based OData service development using the SAP Gateway Service Builder (SEGW) I got the (valid) question from Joachim Rees whether I would commend using SE24 to get the ABAP-Code in the generated classes or whether the developers shouldn't use eclipse for that?

     

    I have to admit that I might have been a little bit old fashioned working mostly with SAPGUI and SEGW/SE24. But ABAP in Eclipse has definitely several advantages when you are developing ABAP code.

     

    However the Service Builder is a SAPGUI transaction and like DDIC structures you have to create your SEGW project using SAPGUI. Fortunately there is a nice integration between ABAP in Eclipse and SAPGUI if you start SAPGUI from within ABAP in Eclipse.

     

    So I thought it would be a good idea to show how to start SEGW from within ABAP in Eclipse.

     

    • Since there has to be at least one ABAP project in your workspace you first have to open the 'ABAP Project Creation Wizard' in order to create a new ABAP project.

    02_Create_ABAP_Project.png

    • You then have to select your system and connect to the same
    • Once you have connected to the system an new folder has been created. Choose the "Open SAPGUI button"

      05_ABAP_PROJECT_CREATED.png
    • You will be prompted on which project the SAPGUI should be launched. Select the newly created project.

    06_start_sapgui_in_project.png

    • SAPGUI will be opened in a new tab. Here we can start SEGW
      07_start_segw.png
    • You can now follow the steps described in my blog OData service development with SAP Gateway - code-based service development - Part I
      08_develop_service.png
    • After you have generated your runtime objects you can edit your classes using ABAP in Eclipse by choosing "Go to ABAP Workbench" when right clicking on the DPC_EXT classe in the Runtime Artifacts folder
      09_goto_abap_workbench.png
    • This will now start ABAP in Eclipse rather than SE24.
      10_edit_in_ADT.png

     

    Have fun using ABAP in Eclipse

    A workaround to have Gateway Tool installed in Eclipse Mars

    Viewing all 137 articles
    Browse latest View live


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