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

Day two at TechEd Bangalore

$
0
0

http://scn.sap.com/community/events/teched/blog/2013/12/13/day-2-sap-netweaver-gateway-at-teched-bangalore-2013

 

Schedule for Friday:

 

Session ID

Session Type

H

Title

Track

Speakers

Session Date/Time/Location

MOB108

Lecture

2 h

Rapid Application and Service Development with SAP Mobile Platform 3.0

Mobile

Balakrishna Gottipati,

Sujith Prathap

Fri, 12/13  8:30a-10:30a

Lounge 12

CD802

Roadmap / Q&A

1 h

Road Map Q&A: SAP NetWeaver Gateway - On-Premise and in the Cloud

Custom Development

Sudeesh K

Fri, 12/13  5p-6p

Show Floor (both sessions)

CD263

Hands On

4 h

ABAP on SAP HANA - Building an End-to-End App from HANA via ABAP to SAP UI5

Custom Development

Vishnu Prasad Hegde, Vaibhav Kumar, Prakash Kamaraj

Fri, 12/13  1:30p-5:30p, HO2

CD265

Hands On

4 h

End-2-End Developer Experience with SAP HANA Cloud Platform and SAPUI5

Custom Development

Rui Nogueira, Ankur Kumar, Stephen Cherian

Fri, 12/13  9a-1p, HO9

 

Session ID

Title

Session owner

Session Date/Time/Location

SPK9750

SAP NetWeaver Gateway - Introduction and Q&A

Sudeesh K

Fri, 12/13  2p-2:30p

Lounge 6

SPK9751

SAP NetWeaver Gateway - Q&A

Sudeesh K

Fri, 12/13  3p-3:30p

Lounge 2

SPK10487

SAP NetWeaver Gateway Services Development Insights

Balakrishna Gottipati

Fri, 12/13 2:30p-3p

Lounge 2


Minimalistic Kick Start to building OData Analytics service

$
0
0
Overview

At times it is required to build a quick prototype or a solution by consuming an OData analytics service. We know that the OData Analytics service can be generated, managed and extended using the SEGW transaction. This is possible from GW 2.0 SP05 onwards. However you could also build an OData Analytics service without using SEGW transaction.

 

However it is recommended to use SEGW; we could create an OData analytics service with minimalistic kick start using the transaction /IWBEP/ANA_SRV_GEN. This transaction is available from GW 2.0 SP04 onwards.

 

Transaction /IWBEP/ANA_SRV_GEN

 

Transaction.JPG

Once the BEP model and BEP service are generated you could proceed to Gateway Hub system in activating the generated service using the transaction /IWFND/MAINT_SERVICE. Once the service is activated you could start using the OData analytics service as explained in the following blog series.

 

Transform SAP BW Queries into OData Service: Part 2 - Analyze OData Analytics Service

GWPAM resolve issue with misnamed embedded Resources

$
0
0

It is a common approach applied by .NET developers to give multipart names to the individual projects in a Visual Studio solution. The name parts identify different aspects of the Visual Studio project, a typical name pattern is  "<CompanyName>.<Application>.<Component>". Example of this: "TNV.Purchase.OrderManagement".

 

 

I applied this naming approach also for a GWPAM project to build a Microsoft Outlook AddIn: TNV.TasksClustering.OutlookAddIn. However, after I installed the compiled AddIn, Outlook failed to load it. The error details were:

 

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Resources.MissingManifestResourceException: Could not find any resources appropriate for the specified culture or the neutral culture.  Make sure "TNV_TasksClustering_OutlookAddIn.Icons.resources" was correctly embedded or linked into assembly "TNV.TasksClustering.OutlookAddIn" at compile time’


I inspected the GWPAM generated code to analyze the problem cause. It appears that GWPAM replaces in the code that it generates, the dots ('.') in the Visual Studio project name into the underline ('_') character. Thus 'TNV.TasksClustering.OutlookAddIn' becomes 'TNV_TasksClustering_OutlookAddIn' in the generated C# code. But a side effect is that this results in a naming-inconsistency with embedded Resources: Visual Studio namely by default embeds .NET resources files in the compiled assembly with the unchanged project name, in this case thus still with the dots.

Naming of embedded resources in GWPAM compiled assembly.jpg

I have reported this issue to the Duet Enterprise / GWPAM product team. I expect it to be fixed in a forthcoming service pack. Until then, the pragmatic and simple workaround is to correct in the generated C# code the line that tries to load the embedded resource:

 

Pragmatic fix to GWPAM dots issue.jpg

Top 5 most liked discussions on SAP NetWeaver Gateway LinkedIn for 2013

Augment GWPAM AddIn project to consume JSON dataformat

$
0
0

GWPAM consumption of efficient JSON format only possible when Gateway service supports OData V3

 

Standard the GWPAM generated AddIns consume the Gateway REST OData service via the AtomPub dataformat, and not via the more data-efficient JSON format. The reason is that the used .Net WCF Data Services Client library is not capable of consuming JSON dataformat. Because I prefer to consume REST services via the mobile-friendly JSON dataformat, I set out to augment a default generated GWPAM Outlook AddIn project to consume via OData JSON. As the service consumption is within .Net code, this is mostly a Microsoft.Net tail. However, as it turns out that to be even able to consume JSON in the Microsoft WCF client library, an important prerequisite is imposed on the consumed REST service; it also extends to there.

 

JSON consumption via WCF Data Services Client Library

Initially, WCF Data Services Client library only supported consumption of REST services via AtomPub dataformat. As of release 5.1 it is also possible to consume JSON, but with the limitation that the JSON format must be OData V3. Prerequisite for the consumed service is thus that it must be able to provide its data in OData JSON V3 dataformat. For the older OData versions (V1, V2), it is not [yet] possible to consume JSON in WCF Data Services Client library.

 

Steps to augment to GWPAM project to consume JSON dataformat

First prepare your project to be able to handle the JSON consumption:

  1. Install the latest WCF Data Services Client Library, at present this is 5.6.0. Installation is done via NuGet Package Manager, and must be applied to each GWPAM project in which you want to consume via JSON dataformat. The effect per project is that reference ‘Microsoft.Data.Services.Client’, version 5.6.0 is added; and that the (via GWPAM project template) already existing references ‘Microsoft.Data.EDM’, ‘Microsoft.Data.OData’, ‘System.Spatial’ are also upgraded to version 5.6.0.
  2. If present, remove the reference ‘System.Data.Services.Client’ from the GWPAM project(s). Note: Visual Studio 2010 default installs with that older WCF Data Services Client library.
  3. Install WCF Data Services 5.3.0 RTM Tools Installer in Visual Studio; also via NuGet.

 

Next setup the consuming code to consume the REST service via OData. That is, if the service supports it

  1. Validate that the consumed service is able to return data in the required JSON dataformat, OData V3. Query for this the $metadata of the service, and validate that it contains “m:MaxDataServiceVersion='3.0'”
  2. Generate an EDMModel for the service, via ‘Add Service Reference’  (iso ‘Add SAP Service Reference’). Open the generated service proxy, and change the accessibility of ‘GeneratedEdmModel’ to public
  3. Edit the earlier generated SAP data services client code to consume the service via JSON dataformat
    1. In the constructor, set to initialize for ‘System.Data.Services.Common.DataServiceProtocolVersion.V3’
    2. Set the Format to link to the generated EDM Model: this.Format.LoadServiceModel =
      TNV.TasksClustering.OutlookAddIn.TaskClusterV3.TasksClusterService.GeneratedEdmModel.GetInstance;
    3. Set the Format to useJson: serviceContext.Format.UseJson()
    4. Copy the implementation + usage of methods ‘ResolveTypeFromName’ and ‘ResolveNameFromType’ from the generated service proxy in step 5. Modify the code to correspond to the full name of the SAP service proxy.

 

GWPAM service modified to consume JSON.jpg

    1. Query the consumed REST service for JSON format; either via querystring param ‘$format=JSON’, or via Http Request Header ‘accept
      = application/json’

 

 

That's it

And that’s it. Now the GWPAM based Office AddIn is able to consume the REST Service via the more efficient JSON dataformat. Note that for the consumption itself it does not even has to a Gateway REST Service; it is also possible to consume REST services from other webservice platforms. But the GWPAM project templates and code generated are focussed on standard SAP NetWeaver Gateway services + data models; WFService as one evident example.

Top 10 achievements for NetWeaver Gateway in 2013

$
0
0

eCATT based Test Automation for ODATA Services available

$
0
0

How to test OData services in SAP NetWeaver Gateway is of great interest for our customers.

 

For testing OData services in SAP NetWeaver Gateway SAP has provided the SAP NetWeaver Gateway Client that can be started using transaction /IWFND/GW_CLIENT. The Gateway Client is a built in REST client that allows to store test cases and run one or more stored test cases in a sequential order. This way it is for example possible to test the CRUD methods of an OData service by creating an object, querying the object, updating the object and finially deleting it.

 

Customers have however requested that SAP would also offer support for performing tests using  Extended Computer Aided Test Tool (eCATT) . eCATT is used by customers frequently to create and execute functional tests. Its primary aim is the automatic testing of SAP business processes. Each test generates a detailed log that documents the test process and results.

 

Though this functionality has not been added to the standard delivery of SAP NetWeaver Gateway our development team decided to publish the
Gateway Test APIs as aproject on Code Exchangein SCN so that it can be leveraged by our customers.

 

With the availability of Gateway Test APIs customer requests can be satisfied to enable eCATT based Test Automation for ODATA Services.

 

Any feedback to the functionality we posted is welcome .

 

Special thanks goes to my colleague Kranti Khilari for working hard on this.

 

Best Regards,

André

 

Links:

 

GITHUB: https://github.com/krantikhil/zsaplink-plugins-for-apis-enabling-test-automation-of-odata-services

Featured Code Exchange projects: http://scn.sap.com/docs/DOC-41875

Custom Gateway service with CRUD Operations and Android application through Eclipse Part 1

$
0
0

In my previous blog Steps to create custom Gateway service and Android application through Eclipse Part 1, I was discussing about getting PO data without CRUD operations and any filter conditions. In this blog I will explain all CRUD operations and how to build an android app based on input values. Before starting, I am expecting that you have basic idea of gateway service or you have gone through my previous blog.

 

Below are the steps we will discuss in this blog.

1. RFC function module with PO Number,Creation Date & PO Release indicator as input parameters.

2. Create service in Gateway system with all the CRUD operations.(Create Read Update Delete)

3. Test our service in 'Service Explorer'.

4. Create Application in Exclipse and test it on Simulator.

 

1. Create a custom RFC Function Module to get PO header and item details. ( Developed in Backend system)

In this FM we have option to pass PO number & Creation date range. I am using custom FM for Read & Query operations only as there is no standard FM to get PO data with input as PO number Range or Date range.

A.  FM: ZBAPI_PO_GETLIST to Read & Query Operations

B.  FM: BAPI_PO_CREATE1 to Create.

C.  FM: BAPI_PO_CHANGE to Delete & Update Operations

FM1.jpg

FM2.jpg

You can get sample code in the attached file.

 

2. Create service in Gateway system with all the CRUD operations.(Create Read Update Delete)

Goto SEGW:

1.jpg

Import Entity type from Data Source

2.jpg

Entity Type for PO

3.jpg

Entity Type for POItems

4.jpg

Create Entity sets, Association and Activate it.

5.jpg

Map data source for READ

6.jpg

7.jpg

8.jpg

Similarly do it for Query , update & delete operations

9.jpg

10.jpg

11.jpg

Similarly map data sorce for POItemSet for Read & Query also

13.jpg

Goto Transaction: /IWFND/MAINT_SERVICE

Select service and add to list

14.jpg

Select service and explore service:

15.jpg

2.jpg

3.jpg

In my next blog Custom Gateway service with CRUD Operations and Android application through Eclipse Part 2 I will explain various combinations of filter conditions and how to test CRUD operations.


SAP NetWeaver Gateway at the Developers Day of the Dutch speaking SAP user group

$
0
0

WP_20140116_008.jpg

In September last year I have been asked by Robert Eijpe from our partner NL for Business (NL4B) to give a presentation about SAP NetWeaver Gateway at the "Developer Dag" (Developer Day) of the VNSG. The VNSG is the Dutch speaking User Group for all SAP and SAP BusinessObjects users in the Netherlands and Flanders which is the Dutch speaking northern part of Belgium.

 

What is not known to most people is that the Dutch speaking SAP user group is the third largest SAP user group in the world!

 

The Deverloper Dag took place this Thursday (January the 15th) in the nice building where the offices of SAP Netherlands and the VNSG are located in s'Hertogenbosch.

 

 

 

An impressive number of 140 developers had registerd for this event so that it was necessary to split the audience for the key notes in two rooms.

 

WP_20140116_009.jpg

 

The event started with a first key note by Robert Eijpe who provided an overview about the interesting and exciting topics that should keep SAP developers enthralled such as HANA, OData, Gateway, Cloud Development etc. 

 

After the key note there was a packed agenda with several sessions in two parallel tracks. 

 

In their presentations Leon Boeijen,R. Eijpe,Robin Fillerup, B. Meijs,Jan Penninkhof and myself covered various topics such as SAPUI5, SAP FIORI, SAP NetWeaver Gateway, HANA XS Development, HANA Cloud Development, Development on top of SAP NetWeaver 740 but also WebDynpro ABAP and FloorPlanManager.

 

 

 

WP_20140116_014.jpg

 

The event was closed by a second key note presented by Nikhil Dhairyawan about the "Future of ABAP". In his presetnation Nikhil highlighted the current innovations & improvements in SAP Application Server ABAP 7.4 and gave the participants a perspective on the role of ABAP in SAP’s platform strategy. We learned that ABAP will live 4ever .

 

For me it was a great time in the Netherlands again and having some time to practive my Dutch.

 

I am looking forward for the next event. Maybe presenting to the upcoming development focus group at VNSG  or by doing another .SAP CodeJam ?

 

 

Use Gateway and SAPUI5 to Connect to External Systems

$
0
0

SAP Gateway has come a long way. It’s actually quite pleasant to develop a quick REST web service these days with it. With the growing presence of Gateway services, the question keeps popping up with our clients on how to connect to non-SAP services. In this blog I’ll show one simple option for using Gateway as a proxy and hosting SAPUI5 application all in one place. Our example is an external contract management application.

 

You can see here how the application will eventually look (SAPUI5):

 

 

 

Our external web service itself uses XML-based REST services. We developed this quickly to demonstrate this application.

 

We have two services. One that includes a list of contracts, and one that goes into the details of a contract.

 

Get a list:

 

 

Get a single contract:

 

 

Next, in ABAP, create a function module to call these services. The function module should utilize the http client class: if_http_client.

 

Use this class to make an outbound web service call, and parse the xml and return it to the function module.

 

It looks like this:

 

 

Use the same concept for the function module for the get details call.

 

Next, jump into Gateway and use transaction SEGW to define your new service. We defined the get list, and get details.

 

In the service implementation we call a remote rfc which are the functions we defined above:

 

 

After activated, you can test out your new OData services:

 

 

So now we can connect our SAPUI5 to Gateway just like any other service!

 

If you haven’t done SAPUI5 in a while, things have really changed. The eclipse add-on is very complex to install, but sure does a great job once you have it. I particularly like the team components which streamline the upload to the BSP. Manually uploading this content was very painful!

 

Create a new SAPUI5 project in eclipse and check it into your ABAP system as a new BSP. Start with the template that creates the index.html

 

And include the controller and view:

 

 

 

This guide is really a lot of help if you haven’t done this before: http://www.sdn.sap.com/irj/scn/go/portal/prtroot/docs/library/uuid/40d59930-791c-3010-2abd-ac7793ad6c57?QuickLink=index&overridelayout=true&59017145615734

 

I created a simple table and set a binding for my get list. I also added an event on a button in the list that creates a dialog popup and gets the details of that contract.

 

Make sure to set your binding to your collection that matches what you have in gateway: oTable.bindRows("/ContractCollection")

 

Once this is complete, you can go into your BSP and test your application:

 

 

It performs very nicely. Clicking on each contract makes another ajax call to the get contract details.

 

For more demonstrations, please see our work at Mindset Consulting: http://www.mindsetconsulting.com/solutions.html

 

You can also follow me (Gavin Quinn) on LinkedIn: http://lnkd.in/gvjKb4

 

Thanks to Paul Modderman, one of my favorite ABAP gurus who provided some incredible guidance on this topic: https://www.linkedin.com/pub/paul-modderman/4/680/39a

eCATT based Test Automation for ODATA Services available

$
0
0

How to test OData services in SAP NetWeaver Gateway is of great interest for our customers.

 

For testing OData services in SAP NetWeaver Gateway SAP has provided the SAP NetWeaver Gateway Client that can be started using transaction /IWFND/GW_CLIENT. The Gateway Client is a built in REST client that allows to store test cases and run one or more stored test cases in a sequential order. This way it is for example possible to test the CRUD methods of an OData service by creating an object, querying the object, updating the object and finially deleting it.

 

Customers have however requested that SAP would also offer support for performing tests using  Extended Computer Aided Test Tool (eCATT) . eCATT is used by customers frequently to create and execute functional tests. Its primary aim is the automatic testing of SAP business processes. Each test generates a detailed log that documents the test process and results.

 

Though this functionality has not been added to the standard delivery of SAP NetWeaver Gateway our development team decided to publish the
Gateway Test APIs as aproject on Code Exchangein SCN so that it can be leveraged by our customers.

 

With the availability of Gateway Test APIs customer requests can be satisfied to enable eCATT based Test Automation for ODATA Services.

 

Any feedback to the functionality we posted is welcome .

 

Special thanks goes to my colleague Kranti Khilari for working hard on this.

 

Best Regards,

André

 

Links:

 

GITHUB: https://github.com/krantikhil/zsaplink-plugins-for-apis-enabling-test-automation-of-odata-services

Featured Code Exchange projects: http://scn.sap.com/docs/DOC-41875

Vocabulary-Based Annotation Support in Service Builder

$
0
0

So far using SAP NetWeaver Gateway you can annotate OData elements only with SAP annotations, now it is possible to enhance the metadata with custom-annotations also and this can be done with vocabulary-based annotation.  Basically vocabularies provide the ability to annotate metadata. A vocabulary file is a namespace that contains terms and these terms are used to annotate OData artifacts.

 

This blog will explain how you can annotate metadata with consumer specific vocabulary using SAP NetWeaver Gateway Service Builder tool.

This feature is available from SAP NetWeaver Gateway SP07.

 

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Step-by-Step Procedure

Following are steps which you need to follow

  • Upload Vocabularies into the Vocabulary Repository
  • Create a Project
  • Import a vocabulary file
  • Add Vocabulary-Based Annotations
  • Generate Runtime Artifact
  • Registration and Activation of the Generated Service

Upload Vocabularies into the Vocabulary Repository

Start the Service Builder by using the transaction SEGW.

 

 

To upload a vocabulary file into the Vocabulary Repository in the Service Builder, proceed as follows:

  1. From menu bar choose Extras ->Vocabulary Repository. The central Vocabulary Repository opens and shows a table for displaying the vocabulary ID, version, namespace, and description. Any previously uploaded vocabulary files are displayed here, otherwise the table is empty.UploadVocabulary.png
  2. Change to edit mode and choose Append Row to add a new row to the table.
  3. Enter a unique vocabulary ID for the vocabulary file you want to upload. Version 1 is assigned automatically to the first version of
    the vocabulary file you upload.
  4. Click the Upload icon in the Upload Vocabulary Content column to navigate to the vocabulary file you want to upload. The namespace of the vocabulary file is entered automatically.
  5. Enter a description for the newly uploaded vocabulary file.
  6. Save the changes and choose Enter.

 

Create a Project

  1. Create a New Project by clicking on 4.jpg

 

  2. Select Service with Vocabulary-Based Annotationsin order to use custom annotations.

Project Type.PNG

  3. Use any of the available options(like Import ,Redefine etc) to create OData service.

 

  Import a vocabulary file

  • In the edit mode, right click on the Data Model, choose Import->Vocabulary in the resulting menu.
  • The Vocabulary Repository window appears.
  • Select the required vocabulary(s) and click continue.

 

VocabularyDialog.PNG

  • In the Tree view a new folder with the name Vocabularies will be created under the Data Model
    and the vocabularies imported into this folder.

Vocabulary Folder.PNG

 

  • Double click on the Terms node under the Vocabularies folder to see the details of the imported annotations in the mass maintenance view.

Terms.png

Note: Terms can be classified into following types

    1. Core Type
    2. Type Definition
    3. Enum Type
    4. Complex Type
    5. Entity Type

 

 

Add Vocabulary-Based Annotations

Once the vocabulary definitions are added to the data model, the terms from the vocabulary definition can be used to annotate the vocabulary based services if the term applies to the respective OData artifacts.

 

To add annotations to artifacts for which vocabularies define applicable terms, proceed as follows:

 

  • Double-click the subfolder that contains the artifacts you want to annotate, for example, Entity Sets. Existing entity sets are listed in the mass maintenance view.

 

EntitySet.PNG

  • Choose the Annotations pushbutton to see the vocabulary that is valid for these entity sets. If more than one vocabulary defines applicable terms, you can select the vocabulary you want to use to annotate the entity set and, if required, toggle between the different vocabularies. If none of the imported vocabularies includes applicable terms for entity sets, for example, this pushbutton is not enabled.

 

Annotations.PNG

  • After you have selected the vocabulary you want to use for the annotations, all entity sets are displayed in a table in the mass maintenance view with the name of the applicable vocabulary displayed as a header.
  • To create annotations for an entity set, select either the entire row to create all available annotations, or select the applicable cells for each annotation you want to create and choose the Create Annotation pushbutton. You can select more than one row and more than one cell to enable the mass maintenance of multiple entity sets and annotations, for example.

 

  • Annotation value can be maintained in Annotation Data table.

EntitysetAnnotation.png

  • If you want to delete any annotations, select the relevant rows or cells and choose the Delete Annotation pushbutton.
  • Save your entries.

 

Generate Runtime Artifact

Vocabulary related code can be found in DEFINE_VOCAB_ANNOTATIONS( ) of  generated MPC class.

 

MPC.PNG

 

In SP7, commented code gets generated for annotation. Follow the instructions provided in method.

 

Registration and Activation of the Generated Service

Refer to section "Registration and Activation of the Generated Service" of my blog on SPI.

You will find new tags namely Annotation Targets in metadata file.

MetaData.PNG

 

That is all for now and if need be this blog be enhanced, stay tuned Any feedback is highly appreciated

Setting up ADFS 2.0 for OAuth2.0 with Netweaver Gateway

$
0
0

This blog post will walk you through how to set up ADFS (Active Directory Federation Services) to work with OAuth2 in Netweaver Gateway. We will be able to set everything up and test it without writing any code. A benefit of this approach is that you know that the issue is not in any new code. This guide was written using ADFS 2.0 and Netweaver Gateway 2.0 SP 7 running on Netweaver 7.4.

 

The scenario we are going to be recreating is the same as in the image below from http://wiki.scn.sap.com/wiki/display/Security/Leave+Request+Approvals+on+Android+-+OAuth+2.0+powered. Before beginning the steps in this blog post, I recommend you complete the netweaver gateway steps described in that link. If your STS (Security Token Service) is ADFS, this blog is for you!

 

Android_OAuth2.0_Demo.png

Before we begin, make sure the following steps are completed:


ssl certificates have been set up on both servers (Gateway and ADFS)

ADFS must already be configured to work with active directory

You have already completed the steps in the configuration guide

 

Log on to your adfs server and open up ADFS 2.0 management

Expand the foloder for trust relationships

Select the folder for Relying party trusts

Click Add Relying Party Trust…


The Add Relying Party Trust Wizard will open, click the start button to begin

Screenshot_1_20_14__2_21_PM.png

 

On the next screen, select the radio button for “Enter data about the relying party manually” and click Next

 

Screenshot_1_20_14__2_22_PM.png

 

Enter a relevant display name and click Next. I chose Netweaver Gateway.

 

Screenshot_1_20_14__2_23_PM.png

 

Ensure that the AD FS 2.0 profile radio button is selected and click Next.

Screenshot_1_20_14__2_24_PM.png

 

You do not need to enter anything for the configure certificate or configure url screens. You can just click next through those. On the Configure Identifiers screen, enter the link used to obtain the oAuth2 token and click add. The link should be: https://yourGatewayServer.com/sap/bc/sec/oauth2/token

 

Screenshot_1_20_14__2_29_PM.png

 

On the next screen you can choose to allow all users to access this service or deny all users. You response will depend on how much you want to restrict access for oAuth services. Since users will be logged in when accessing your backend data, the sap roles should be sufficient control, so I recommend selecting the permit all users to access this relying party radiobutton.

 

Screenshot_1_20_14__4_43_PM.png

 

Lastly, review the settings and click next to add Netweaver Gateway as a relying party trust.

 

Then select your newly created relying party trust and click Edit Claim Rules…

 

You exact setting for the claim rules will depend on your system, but SAP is very specific on how the username is passed.


For example:

This works:<NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">oneillb</NameID>

This does not:<NameID>oneillb</NameID>

 

In order to get the format to come through correctly, I found that you need to have two transform rules. The first one pulls the value and the second one sets the format. Additionally, the outgoing claim type must be different between the first and second rule.

 

Here is an example for pulling a username (you may want to use email instead). This may be slightly different depending on your active directory configuration.

 

When creating the first rule, select the template for Send LDAP Attributes as Claims and click next.

 

Screenshot_1_20_14__5_05_PM.png

 

I called my first rule Load username to Common Name. For me, the attribute was SAM-Account-Name and I used common Name as the outgoing claim type.

Screenshot_1_20_14__5_04_PM.png

For the next rule, select the rule template Transform an Incoming Claim.

 

Microsoft_Word.png

 

This is where you select the common name type that we set up in the previous rule and transform it to an unspecified Name ID. Note: This did not work for me when going from a Name ID to a Name ID, so make sure you are going from Common Name to Name ID.

 

Screenshot_1_20_14__5_14_PM.png

 

Your two rules should look like my screenshot below and be in the same order.

 

Screenshot_1_20_14__5_15_PM.png

 

We are now ready to test! We are going to test this using curl, but you could do the same function with custom code. I like using curl so we can quickly test and adjust until it works!

 

So First you need to create your request. Create the below xml request in a text editor such as textWrangler or notepad ++ (not MS word) and save the document as request.txt. Items that you need to change are inred.

 

<?xml version="1.0" encoding="utf-8"?>

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">

            <s:Header>

                        <a:Action s:mustUnderstand="1">

 

http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</a:Action>

                        <a:To s:mustUnderstand="1">https://YourADFSServer.com/adfs/services/trust/13/UsernameMixed</a:To>

                        <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" >

                                    <o:UsernameToken>

                                                <o:Username>YourUsername</o:Username>

                                                <o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">YourPassword</o:Password>

                                    </o:UsernameToken>

                        </o:Security>

            </s:Header>

            <s:Body>

                        <trust:RequestSecurityToken xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">

                                    <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">

                                                <a:EndpointReference>

                                                            <a:Address>https://YourNetweaverGatewayServer.com/sap/bc/sec/oauth2/token</a:Address>

                                                </a:EndpointReference>

                                    </wsp:AppliesTo>

                                    <trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>

                                    <trust:RequestType>

 

http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>

                                    <trust:TokenType>urn:oasis:names:tc:SAML:2.0:assertion</trust:TokenType>

                        </trust:RequestSecurityToken>

            </s:Body>

</s:Envelope>

 

Now lets send that request to our ADFS server with the following curl command:

curl https://YourADFSServer.com/adfs/services/trust/13/usernamemixed --data @request.txt -H "Content-Type:application/soap+xml"  --verbose -o "output.txt"

 

Now you can open output.txt and see the result. You should see a NameID formatted like this: <NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">username</NameID> Or similar formatting if you are using email instead. If you format the result for easier xml reading make sure you undo that before continuing.

 

Remove everything outside of the <assertion></assertion> tags and save the file.

 

Now base64 encode the assertion and replace your xml with the encoded result This can be done using the website http://www.base64encode.org

 

Next you need to url encode the base64 encoded assertion. You can do this through the website http://meyerweb.com/eric/tools/dencoder/

 

Now, append the following before the encoded assertion:

client_id=YourClientID&scope=YourScope&grant_type=urn:ietf:params:oauth:grant-type:saml2-bearer&assertion=YourAssertion

 

Save this as output.txt

 

Now we want to send that base64 encoded assertion to our SAP Netweaver Gateway server in order to get an oAuth2 token. You can do this with the below curl operation. The User:Password is the username and password created as the oAuth client system user described at http://wiki.scn.sap.com/wiki/display/Security/OAuth+2.0+Client+Registration+for+the+SAML+Bearer+Grant+Type

 

curl "https://YourNetweaverGatewayServer.com/sap/bc/sec/oauth2/token" --data @output.txt -k --user "USER:PASSWORD(base64encoded)" -H "Content-Type:application/x-www-form-urlencoded" --verbose -o "sapOut.txt"

 

The response from Netweaver gateway should look like the below. The access token is encrypted and will be used when calling your webservice

 

{ "access_token":"TOKEN","token_type":"Bearer","expires_in":"3600","scope":"YourScope" }

 

Your can now (finally!) call your webservice with this token in a curl command like the below:

curl "https://YourNetweaverGatewayServer.com/sap/opu/odata/sap/YourService /?$format=json" -k -H "Authorization: Bearer YourToken" --verbose -o "sapOut2.txt"

 

You should hopefully see the resulting data in the sapOut2.txt file!

 

If so, congratulations everything works and your ready to create an app that can do all of the steps that you were doing in curl!

 

My next post is going to be about what I would love to see changed about this oAuth2 implementation.

 

If you found this useful, please leave a comment about how you are or planning to use oAuth. Also, please let me know if you notice anything that I am doing wrong or could be doing differently. Thanks!

Deploying SAP NetWeaver Gateway in mixed (7.40 and earlier) environments

$
0
0

With a growing number of customers deploying systems that are based on SAP NetWeaver 7.40 I am getting more often the question how to deploy SAP NetWeaver Gateway in system landscape because it is not clear which service pack of SAP NetWeaver Gateway 2.0 fits to which service pack of SAP NetWeaver 7.40 where Gateway is part of the Basis.

 

While I have discussed the question of deployment options in my blog SAP NetWeaver Gateway deployment options in a nutshell this blog so far did not answer the question which service pack of SAP NetWeaver Gateway 2.0 should be deployed in a SAP Business Suite backend system if the SAP NetWeaver Gateway server is for example running on SAP NetWeaver 7.40 SP4.

 

To answer this question now and in the future we have published SAP Note 1942072 - SAP NetWeaver Gateway 2.0 Support Package Stack
Definition
which describe which SP level on 7.40 is equivalent to which SP level of SAP NetWeaver Gateway 2.0 running on a release prior to 7.31.

 

To answer the question raised above :

 

... the customer should choose IW_BEP 200 SP07 if the hub runs on top of 7.40 SP04.

 

Best Regards,

Andre

OData producer using Apache Olingo with MySQL, JPA & Tomcat web server

$
0
0

Exposing MySQL database or any database as OData service endpoint using JPA (JAVA Persistence API) and Apache Olingo OData library on Apache Tomcat web server. The JPA Model can be exposed in the form of OData service endpoint, which allows the data to be accessed via http based protocol.

 

For more details on OData, please refer http://www.odata.org/

 

(I had a scenario, UI5 Application should run on SAP NetWeaver Gateway and as well in other OData source).

 

Developing of the OData endpoint using JPA Model and deployment of the OData service in Apache Tomcat in 7 steps.


Table of Contents




Prerequisite

  • MySQL Server 5.x
  • Apache Tomcat 7.x
  • Eclipse Kepler / Juno preferably J2EE edition
  • Dependent libraries refer topic 3


1. Create a dynamic web project in Eclipse

  • Launch Eclipse from extracted folder by double click eclipse.exe to open it. Eclipse will ask you for workspace location. Specify a location and click ok
  • To create a Dynamic Web Project, File -> New -> Dynamic Web Project as shown
  • Enter the project name for example "emplist-web"
  • In Target runtime Click on “New Runtime...” button to define Apache Tomcat v7.0 as HTTP server to expose our JPA Model as OData service endpoint. Provide your Apache Tomcat Server folder in Tomcat installation directory.

Tomcat1.png

  • Click on “Modify...” button in the above window and in opened window, select the “JPA” check box and click on “OK” button

Tomcat2.png

  • In the next window, choose Platform “EclipseLink 2.5.x”, JPA implementation Type: “Disable Library Configuration”, radio button “Annotated classes must be listed in persistence.xml” and click on the “Next” button

Tomcat3.png

  • In the "Java - src" window, click on the “Next” button
  • In the "Web Module" window, check “Generate web.xml deployment descriptor” and click on the “Finish” button. Now project has been created in the project explorer window

Tomcat4.png

2. Create a MySQL connection to be exposed as OData service endpoint

  • To create a MySQL Database connection, in the menu, Windows -> Show View -> Data Source Explorer
  • Go to “Data Source Explorer” tab, Right click on “Database Connection” node and click on “New...” menu item
  • In the Connection Profile window, select MySQL and click on "Next" button
  • Configure the MySQL JDBC Driver i.e. add latest driver by removing non existent old driver.
  • Specify the name for Database field and URL field end
  • Enter the Username, Password and click "Test Connection" button ensure DB connection Ping succeed.

MySQL1.png

  • In the “Data Source Explorer”, now you can see the MySQL connection and expand to see DB objects

MySQL2.png

3. Add the dependent libraries to the Project

Download and copy the required libraries to “<your eclipse project>/WebContent/WEB-INF/lib” folder.


AddLib1.png

  1. JPA: Add EclipseLink and JPA Persistence JAR files to “Lib” folder
    1. eclipselink.jar
    2. javax.persistence_2.1.0.v201304241213.jar
  2. Database: Add MySQL connector java to “Lib” folder
    1. mysql-connector-java-5.1.28-bin.jar
  3. OData: Add Apache Olingo OData libraries JAR files to “Lib” folder
    1. olingo-odata2-core-incubating-1.0.0.jar
    2. olingo-odata2-api-incubating-1.0.0.jar
    3. olingo-odata2-api-annotation-incubating-1.0.0.jar
    4. olingo-odata2-jpa-processor-core-incubating-1.0.0.jar
    5. olingo-odata2-jpa-processor-api-incubating-1.0.0.jar
    6. javax.ws.rs-javax.ws.rs-api-2.0-m10.jar
  4. Service: Other libraries required    (main: http://central.maven.org/maven2/org/apache/cxf/)
    1. cxf-api-2.7.5.jar                          (../cxf-api/2.7.5/cxf-api-2.7.5.jar)
    2. cxf-rt-bindings-xml-2.7.5.jar          (../cxf-rt-bindings-xml/2.7.5/cxf-rt-bindings-xml-2.7.5.jar)
    3. cxf-rt-core-2.7.5.jar                     (../cxf-rt-core/2.7.5/cxf-rt-core-2.7.5.jar
    4. cxf-rt-frontend-jaxrs-2.7.5.jar       (../cxf-rt-frontend-jaxrs/2.7.5/cxf-rt-frontend-jaxrs-2.7.5.jar)
    5. cxf-rt-transports-http-2.7.5.jar      (../cxf-rt-transports-http/2.7.5/cxf-rt-transports-http-2.7.5.jar)
  5. Links: downloading for libraries
    1. JPA: http://www.eclipse.org/eclipselink/downloads/
    2. MySQL DB driver: http://dev.mysql.com/downloads/connector/j/
    3. OData: http://www.apache.org/dyn/closer.cgi/incubator/olingo/odata2/rel-1.0.0/olingo-odata2-dist-jpa-incubating-1.0.0-jpa.zip
    4. Service: There itself


  • After copying libraries to “/WebContent/WEB-INF/lib” folder, go to menu “Project” -->“Clean” and select your project by choosing “Clean projects selected below” and click on “OK” button.
  • After creating JPA entities from table, Eclipse shows error then rightclick on “WebContent/WEB-INF/lib” folder and choose “Validate” menu item.

4. Create a JPA Model from MySQL database connection

  1. To create JPA Model, go to File --> New --> Other --> JPA Entities from Tables and click on next button

    JPA1.png

  2. Select MySQL connection and click connection button and select the schema where tables are available. Choose tables to be exposed as OData service and check “List generated classes in persistence.xml” and next window is “Table Associations”, here just click “Next” button.

    JPA2.png

  3. In Next window, check “Always generate optional JPA annotations and DDL parameters” and package can be configured here (com.<your company>.<project name>.model) and click on “Next” button.
  4. Next window click on “Finish” button.
  5. Now in “src” folder, Java classes are created as JPA Model entities.

    JPA3.png

  6. Double click on “persistence.xml” and select the tab “Connection”
  7. Transaction type: choose “Resource local” and EclipseLink connection pool area click on link “Populate from connection...” and choose Local MySQL and will populate the connection fields.

    JPA4.png

  8. Click source or select “persistence.xml” file from your project explorer will contain as follows

<?xmlversion="1.0"encoding="UTF-8"?>

<persistenceversion="2.1"xmlns="http://xmlns.jcp.org/xml/ns/persistence"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistencehttp://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">

       <persistence-unitname="emplist-web"transaction-type="RESOURCE_LOCAL">

              <class>model.Employee</class>

              <class>model.Group</class>

              <properties>

                     <propertyname="javax.persistence.jdbc.url"value="jdbc:mysql://localhost:3306/test"/>

                     <propertyname="javax.persistence.jdbc.user"value="root"/>

                     <propertyname="javax.persistence.jdbc.password"value="King1234"/>

                     <propertyname="javax.persistence.jdbc.driver"value="com.mysql.jdbc.Driver"/>

              </properties>

       </persistence-unit>

</persistence>

 

After creating JPA entities from table, Eclipse shows error then right click on “WebContent/WEB-INF/lib” folder and choose “Validate” menu item.


5. Expose your JPA Model as OData service using Apache Olingo

To Expose the JPA Model from MySQL as OData service, we use Apache Olingo library. For more information: http://olingo.incubator.apache.org/

 

Using Olingo, exposing JPA Model as OData service simple and it consists of three steps

 

  • Extend the “ODataServiceFactory” class (EmployeeListServiceFactory.java)
  • Create the new class “EmployeeListServiceFactory.java” in package “main” with following code (copy paste).

package main;

 

import javax.persistence.EntityManagerFactory;

import javax.persistence.Persistence;

 

import org.apache.olingo.odata2.processor.api.jpa.ODataJPAContext;

import org.apache.olingo.odata2.processor.api.jpa.ODataJPAServiceFactory;

import org.apache.olingo.odata2.processor.api.jpa.exception.ODataJPARuntimeException;

 

 

publicclass EmployeeListServiceFactory extends ODataJPAServiceFactory {

 

  privatestaticfinal String PERSISTENCE_UNIT_NAME = "emplist-web";

 

  @Override

  public ODataJPAContext initializeODataJPAContext()

      throws ODataJPARuntimeException {

 

    ODataJPAContext oDatJPAContext = this.getODataJPAContext();

    try {

 

      EntityManagerFactory emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);

oDatJPAContext.setEntityManagerFactory(emf);

      oDatJPAContext.setPersistenceUnitName(PERSISTENCE_UNIT_NAME);

 

      return oDatJPAContext;

 

    } catch (Exception e) {

 

      thrownew RuntimeException(e);

 

    }

 

  }

 

}

  • Add necessary tags in “web.xml” file
  • Copy the contents in <servlet> and <servlet-mapping> tags

<?xmlversion="1.0"encoding="UTF-8"?>

<web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"id="WebApp_ID"version="3.0">

  <display-name>emplist-web</display-name>

  <welcome-file-list>

    <welcome-file>index.html</welcome-file>

  </welcome-file-list>

 

  <servlet>

    <servlet-name>ODataServlet</servlet-name>

    <servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class>

 

    <init-param>

      <param-name>javax.ws.rs.Application</param-name>

      <param-value>org.apache.olingo.odata2.core.rest.app.ODataApplication</param-value>

    </init-param>

 

    <init-param>

      <param-name>org.apache.olingo.odata2.service.factory</param-name>

      <param-value>main.EmployeeListServiceFactory</param-value>

    </init-param>

 

    <load-on-startup>1</load-on-startup>

  </servlet>

 

  <servlet-mapping>

    <servlet-name>ODataServlet</servlet-name>

    <url-pattern>/emplist.svc/*</url-pattern>

  </servlet-mapping>

 

</web-app>

  • Add “index.html” to “WebContent” (Right click -> New HTML file) folder with following content

<!DOCTYPEhtml>

 

<html>

    <head>

        <metacharset="utf8">

        <title>Employee List OData</title>

    </head>

    <body>

        <h1>Employee List OData</h1><br><br>

        <ahref="/emplist-web/emplist.svc/">Service Document</a>

    </body>

</html>

6. Testing OData service endpoint

  • Right click on your project in “Project Explorer”, select menu items “Run As” -> “Run on Server”.
  • In the window, choose “Tomcat v7.0 Server at localhost” and click on “Finish” button
  • After successfully web application deployed, you will get the below window (internal browser) or configured browser. In browser, “index.html” is shown and by clicking the link “Service Document”. Browser will show your OData Service document (http://localhost:8080/emplist-web/emplist.svc/). Better use Google Chrome browser. To access OData Metadata Service document add $metadata in the link (http://localhost:8080/emplist-web/emplist.svc/$metadata)

 

7. OData service in CORS

  • Cross-origin resource sharing (CORS) is a mechanism that allows JavaScript on a web page to make XMLHttpRequests (AJAX calls) to another domain, not the domain the JavaScript originated from. Such "cross-domain" requests would otherwise be forbidden by web browsers, per the same origin security policy.
  • UI5 application developed in other domain, requires access to your OData service forbidden by browsers.
  • Allow access to OData service in other domain (CORS) then configure below tags in “/WebContent/ WEB-INF/web.xml” file in your project or globally for all web application then update in Apache Tomcat Server folder “/conf/web.xml”.

 

 

  <!-- CORS To allow access OData service by JavaScript in other domain  -->

  <filter>

      <filter-name>CorsFilter</filter-name>

      <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>

  </filter>

  <filter-mapping>

      <filter-name>CorsFilter</filter-name>

      <url-pattern>/*</url-pattern>

  </filter-mapping>



Gateway, the ICF and solving the "Same Origin Policy"

$
0
0

Intro

After all the theoratical introductions at recent SAP TechEd Events and some smaller projects in a local sandbox system I was finally getting to develop my own first Gateway based ODATA service that should be consumed by some website running jQuery. Setting up our little service, creating some entities, etc. was nothing really special after all the introductions and the excellent learning material in SCN.

 

Real world scenario issues

Of we go, our website development colleagues have included the provided service URI and are trying to read data from our service. Nothing happens within the jQuery script compared to directly calling the service in a browser where we get a nice response. What happened?

Looking into Chrome's excellent developer tools we get a pointer to our issue:

chrome_error.jpg

We're continuing our journey with tools from Google and finally end up getting really useful inside on 'Cross Origin Ressource Sharing'. I recommend to have a look at the following:

 

Options

Looking at the blog post from Michael Herzog I would have loved to use JSONP (as outlined in a custom handler in this post). Unfortunately (to my knowledge) NetWeaver Gateway is currently not supporting JSONP and I didn't wanted to give up the complete Gateway framework and write a handler from scratch as outlined in mentioned blog from Alessandro Spadoni.

Setting up a proxy on the server providing the website would have been an option although I wanted to avoid this for two reasons: additional server load and being able to solve this problem on my own within Gateway.

So, next option would be sending an appropriate 'Access-Control-Allow-Origin' header in the response. I was unable to find any Gateway specific documentation regarding customizing so it seemed we need to take care of this on our own.

 

Adding the http header

The first and most appealing option of course would be to add the header directly in our service extension. And the good news is that one is actually able to do this. Right within your 'DPC_EXT' class you get access to method /IWBEP/IF_MGW_CONV_SRV_RUNTIME~SET_HEADER which can be used to set additional header fields. Nice and our first solution is working already.

 

Extending the solution

Now that we have the first solution in place I wanted to extend this a little bit in order to not send '*' as the allowed requester and with this enabling everyone who is able to call my server to execute this service within his website. In other words I wanted to check the requester against a small customer table which would whitelist potential consumers of my service. However I was not able to get access to the needed http header field 'Origin' from the request to determine the requester.

Instead of using the service method of the entity I decided to write a small custom http handler which I could hook into SICF and which would check the requester and if ok add the header field. I won't go into the details of writing the http handler class as such. This should be documented enough around here.

However when hooking the additional handler into SICF I stumbled over the following issues which I wanted to share to make life a little bit easier.

Order of execution of handler classes and flow of handlers

First of all our little handler class needs to be executed before the standard handler /IWFND/CL_SODATA_HTTP_HANDLER. Otherwise it will never be reached because after execution of the standard handler attribute if_http_extension~flow_rc will be set to 0 (or CO_FLOW_OK) which will tell the framework to not process any other handlers because request processing is complete. You can read more about this in SAP Help.

 

Second crucial point: the order of execution is top to bottom, in other words the handler maintained in node 'odata' will be executed first and only after that the handler in your actual SICF service down the line will be executed. Combining this with the knowledge about flow the handler on the service node will probably never be reached and in theory could be deleted. We will have to add our custom handler in node 'odata' in order to make it work.

To find out about order of execution of handler classes I would recommend the following blog by Christian Buckowitz: Debugging into a HTTP request on AS ABAP.

 

So, finally we have everything in place, added our little handler into first place in node 'odata' but still nothing happens, a break-point in our custom handler code is not reached. What is going wrong? It took me a while to figure this one out. However by looking at function module 'HTTP_GET_HANDLER_LIST' it became clear that changes in SICF might not immediately be reflected during runtime as we have a parameter named 'SHM_PARAM'. Shared memory seems to be involved and indeed, looking into transaction SHMM in our system one can easily spot an area which seems to used for ICM:

shmm.jpg

After having deleted this area our changes towards the handler list of node 'odata' had finally an impact on runtime processing and our little handler does his magic to check the request and add the header.

 

Final remarks and a word of caution

I would strongly suggest to keep in mind that you are adding your own logic towards the processing of requests inside of Gateway if you follow the example given inside this blog. This could have all kind of side effects towards processing, security, etc. so be careful.

 

Finally: I hope you did like the blog and hope that it invokes some discussion towards the route taken. It would be especially nice to get some information on whether something is in the pipeline for Gateway to solve this in SAP standard and whether Gateway will support JSONP in the future. Of course one could write their own JSONP handler extending Gateway. May be this is something for a follow-up blog.

Upcoming Webinars - Liberate your SAP Data with SAP NetWeaver Gateway

$
0
0

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


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


Dear Customer/Partner,

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

 

Efficiently meet IT challenges:

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


Efficiently integrate Teams, Data, and Processes

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

 

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


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

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

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

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

registerCustomer.png                      registerpartner.png

 

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

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

registerCustomer.png                       registerpartner.png

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

$
0
0

Introduction

 

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


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


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

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

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

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

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

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


 

Scenario

 

We have User information table as ZUSERINFO containing below fields

gw1.jpg

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


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

 

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


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


Entity SetTable Type or Internal Table
EntityStructure or Work Area



Procedure


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

gw2.jpg

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

gw3.jpg

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

gw4.jpg

finally our entity type User will look as below.

gw5.jpg

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


I will go with UserCollection as my entity set name.


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

gw6.jpg

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

gw7.jpg

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

gw8.jpg

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

gw9.jpg

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


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

gw10.jpg

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

 

Coding


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


1) Query Operation


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

gw11.jpg

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

gw12.jpg

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

METHOD usercollection_get_entityset.

 

  DATA: lt_userinfo TYPETABLEOF zuserinfo,

        ls_userinfo LIKELINEOF lt_userinfo,

        ls_entity   LIKELINEOF et_entityset.

 

*Get data from ZUSERINFO table

  SELECT * FROM zuserinfo INTOTABLE lt_userinfo.

 

*Fill ET_ENTITYSET

  LOOPAT lt_userinfo INTO  ls_userinfo .

    ls_entity-userid    = ls_userinfo-userid.

    ls_entity-firstname = ls_userinfo-firstname.

    ls_entity-lastname  = ls_userinfo-lastname.

    ls_entity-email     = ls_userinfo-email.

    ls_entity-phone     = ls_userinfo-phone.

    ls_entity-country  = ls_userinfo-country.

    APPEND ls_entity TO et_entityset.

  ENDLOOP.

 

ENDMETHOD.

 

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


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

gw13.jpg

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


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


Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_ENTITYSET


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

UserCollection?$orderby=FirstName,LastName


OR


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

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

 

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


 

2) Read Operation


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


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

METHOD usercollection_get_entity.

 

DATA:  ls_key_tab   TYPE /iwbep/s_mgw_name_value_pair,

        lv_userid   TYPE zuserinfo-userid,

        ls_userinfo TYPE  zuserinfo.

 

*Get the key property values

READTABLE it_key_tab WITHKEY name = 'UserID'INTO ls_key_tab.

 

  lv_userid = ls_key_tab-value.

 

*Get the single record from ZUSERINFO and fill ER_ENTITY

SELECTSINGLE * FROM zuserinfo INTO ls_userinfo WHERE userid = lv_userid.

  IF sy-subrc = 0.

    er_entity-userid    = ls_userinfo-userid.

    er_entity-firstname = ls_userinfo-firstname.

    er_entity-lastname  = ls_userinfo-lastname.

    er_entity-email     = ls_userinfo-email.

    er_entity-phone     = ls_userinfo-phone.

    er_entity-country   = ls_userinfo-country.

  ENDIF.

 

ENDMETHOD.

 

Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_ENTITY

 

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

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

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

 


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


3) Create Operation


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


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

METHOD usercollection_create_entity.

  DATA: ls_request_input_data TYPE zcl_zuserinfo_mpc=>ts_user,

        ls_userinfo TYPE zuserinfo.

 

* Read Request Data

  io_data_provider->read_entry_data(IMPORTING es_data = ls_request_input_data ).

 

* Fill workarea to be inserted

  ls_userinfo-userid   = ls_request_input_data-userid.

  ls_userinfo-firstname = ls_request_input_data-firstname.

  ls_userinfo-lastname = ls_request_input_data-lastname.

  ls_userinfo-email    = ls_request_input_data-email.

  ls_userinfo-phone    = ls_request_input_data-phone.

  ls_userinfo-country  = ls_request_input_data-country.

 

* Insert Data in table ZUSERINFO

  INSERT zuserinfo FROM ls_userinfo.

  IF sy-subrc = 0.

    er_entity = ls_request_input_data."Fill Exporting parameter ER_ENTITY

  ENDIF.

ENDMETHOD.

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


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

gw14.jpg

So correct steps are,

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

2) Click Use as Request button

3) Update your request properties.

4) Select HTTP method as POST

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

gw15.jpg


Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_ENTITY_C


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


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

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


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

 

4) Update Operation


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

METHOD usercollection_update_entity.

  DATA:  ls_request_input_data TYPE zcl_zuserinfo_mpc=>ts_user,

         ls_key_tab            TYPE /iwbep/s_mgw_name_value_pair,

         lv_userid             TYPE zuserinfo-userid,

         ls_userinfo           TYPE zuserinfo.

* Get key values

  READTABLE it_key_tab WITHKEY name = 'UserID'INTO ls_key_tab.

  lv_userid = ls_key_tab-value.

  IF lv_userid ISNOTINITIAL.

 

* Read request data

    io_data_provider->read_entry_data(IMPORTING es_data = ls_request_input_data ).

 

* Update fields of table ZUSERINFO

    UPDATE zuserinfo SET firstname = ls_request_input_data-firstname

                         lastname  = ls_request_input_data-lastname

                         email     = ls_request_input_data-email

                         phone     = ls_request_input_data-phone

                         country   = ls_request_input_data-country

                         WHERE userid  = lv_userid.

    IF sy-subrc = 0.

      er_entity = ls_request_input_data."Fill exporting parameter ER_ENTITY

    ENDIF.

  ENDIF.

ENDMETHOD.

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

gw16.jpg

Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_ENTITY_U


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

DATA: lt_keys TYPE /iwbep/t_mgw_tech_pairs,

     ls_key TYPE /iwbep/s_mgw_tech_pair.

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

 

5) Delete Operation


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


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

METHOD usercollection_delete_entity.

  DATA:  ls_key_tab TYPE /iwbep/s_mgw_name_value_pair,

         lv_userid TYPE zuserinfo-userid.

* Read key values

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

  lv_userid = ls_key_tab-value.

  IF lv_userid ISNOTINITIAL.

* Delete record from table ZUSERINFO

    DELETEFROM zuserinfo WHERE userid = lv_userid.

  ENDIF.

ENDMETHOD.

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

gw17.jpg

Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_ENTITY_D

 

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

DATA: lt_keys TYPE /iwbep/t_mgw_tech_pairs,

     ls_key TYPE /iwbep/s_mgw_tech_pair.

  lt_keys = io_tech_request_context->get_keys( ).
Yes

 

6) Function Import 

 

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

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

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

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

  • Confirm Work Item
  • Check Flight Availability

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

 

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


Suppose our ZUSERINFO table looks like below,

gw18.jpg

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

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

gw19.jpg

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

gw20.jpg

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

gw21.jpg

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

gw22.jpg

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

Put below code to implement function import.

METHOD /iwbep/if_mgw_appl_srv_runtime~execute_action.

  DATA: ls_parameter  TYPE /iwbep/s_mgw_name_value_pair,

        lv_country    TYPE string,

        lt_userinfo   TYPETABLEOF zuserinfo,

        ls_userinfo   TYPE zuserinfo,

        ls_entity     TYPE  zcl_zuserinfo_mpc=>ts_user,

        lt_entityset  TYPE zcl_zuserinfo_mpc=>tt_user.

 

 

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

    IF it_parameter ISNOTINITIAL.

* Read Function import parameter value

      READTABLE it_parameter INTO ls_parameter WITHKEY name = 'Country'.

      IF sy-subrc = 0.

        lv_country = ls_parameter-value.

      ENDIF.

 

      IF lv_country ISNOTINITIAL.

        SELECT  * FROM zuserinfo INTOTABLE lt_userinfo WHEREcountry = lv_country.

        LOOPAT lt_userinfo INTO  ls_userinfo .

          ls_entity-userid   = ls_userinfo-userid.

          ls_entity-firstname = ls_userinfo-firstname.

          ls_entity-lastname = ls_userinfo-lastname.

          ls_entity-email    = ls_userinfo-email.

          ls_entity-phone    = ls_userinfo-phone.

          ls_entity-country  = ls_userinfo-country.

          APPEND ls_entity TO lt_entityset.

        ENDLOOP.

* Call methos copy_data_to_ref and export entity set data

        copy_data_to_ref(EXPORTING is_data = lt_entityset

                CHANGING cr_data = er_data ).

 

      ENDIF.

    ENDIF.

  ENDIF.

 

ENDMETHOD.

 

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


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

gw23.jpg

Here IO_TECH_REQUEST_CONTEXT refers to /IWBEP/IF_MGW_REQ_FUNC_IMPORT


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

 

 

Closing Remarks

 

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

 

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

 

Happy Learning & Coding

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

$
0
0

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


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


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


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


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


Prerequisites

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


Read

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


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


Read Prerequisites: EDM/$metadata


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


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

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


Read Entity: Product


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

 

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

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


Read Entities: ProductCollection


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


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

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

All used URIs


Navigate

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

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

All used URIs


Read more with Expand

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


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

 

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

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

 

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

All used URIs

Read more with Expand on a Feed


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

All used URIs


Read less with Select

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


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

 

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

All used URIs


Conclusion

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

Runnable sample client

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


To run this sample follow these steps:


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

Step by step guides for OAuth 2.0 with NetWeaver Gateway

Viewing all 253 articles
Browse latest View live




Latest Images