cancel
Showing results for 
Search instead for 
Did you mean: 

SMP 3.0 OData Offline Create/Update/Delete

Former Member
0 Kudos

Hello,

We are experiencing issues related to SAP Mobile Platform 3.0 OData Offline functionalities.

The development scenario is Android native with SAP Mobile Platform 3.0 SDK SP06.


After succesfully implementing user onboarding/registration, creating the offline store and reading data from an SAP ERP back-end system using delta tokens, we seem to have difficulties with Create/Update/Delete operations.

The Create/Update/Delete operations were implemented according to SAP documentation and examples using the following SMP SDK functions:

  • ODataOfflineStore.scheduleCreateEntity
  • ODataOfflineStore.schedulePatchEntity or ODataOfflineStore.scheduleUpdateEntity
  • ODataOfflineStore.scheduleDeleteEntity


When testing the functions, we get the following 403 Forbidden error (at SMP server level):


#2.0#2015-02-02 12:02:47.472#+0:00##Proxy####1422878567458001#ee1c9f3f-aaf4-11e4-8000-be50499ead5a#com.fv.zsfasrv#DirectProxy:handle#smpAdmin#######284###Finished OData Proxy Request:https://smp3.mobile.local:8083/gateway/odata/SAP/ZSFA_SRV/PersonCollection('T-S62C19')#

#2.0#2015-02-02 12:02:47.47#+0:00#FATAL#Proxy####1422878567458000#ee1c9f3f-aaf4-11e4-8000-be50499ead5a#com.fv.zsfasrv#DirectProxy:handle#smpAdmin#######284###Response code from Backend403Forbidden#

#2.0#2015-02-02 12:02:47.454#+0:00##Proxy####1422878566278000#ee1c9f3f-aaf4-11e4-8000-be50499ead5a#com.fv.zsfasrv#DirectProxy:handle#smpAdmin#######284###Finished OData Proxy Request:https://smp3.mobile.local:8083/gateway/odata/SAP/ZSFA_SRV/$metadata#


After testing and investigation of the matter, we have reasons to believe the error might be related to the X-CSRF token.

Considering we were led to believe that the Offline SDK handled tokens and cookies automatically, we are unsure about how to proceed in solving the issue.


Consequently, we would appreciate some help regarding Create/Update/Delete operations on an ODataOfflineStore and X-CSRF token/cookies management.


- EDIT 1

After further tweaking, we managed to get a more detailed log, please see attached TraceFile.txt.



Thank you.

Regards,

~ Valentin Alexandru Tudorache

Accepted Solutions (0)

Answers (2)

Answers (2)

agentry_src
Active Contributor
0 Kudos

Discussion successfully moved from SAP for Mobile to SMP Developer Center as the more appropriate community for this topic.

Regards, Mike (Moderator)

SAP Technology RIG

Jitendra_Kansal
Product and Topic Expert
Product and Topic Expert
0 Kudos

To ensure if Create/Update/Delete operations are working fine at backend level, did you check it in REST client first? Have a look here.

If you are able to execute it successfully, then there might be something wrong with your code. Can you share the code?

Did you get a chance to look at document ?

Regards,

JK

Former Member
0 Kudos

First of all, yes, we have tested with the REST client. This was mainly the method with led us to believe the problem is related to the X-CSRF token and/or the cookies.

Secondly, yes, we have checked all the available documentation (and code samples) on the matter.

Thirdly, I will attach a code snippet with the functions we implemented.

- EDIT 1

Added code snippet for Create/Update/Delete functions, please see attached CreateUpdateDelete.txt.

Thank you.

Regards,

~ Valentin Alexandru Tudorache

Jitendra_Kansal
Product and Topic Expert
Product and Topic Expert
0 Kudos

First of all, yes, we have tested with the REST client. This was mainly the method with led us to believe the problem is related to the X-CSRF token and/or the cookies.

What did you get in the RESPONSE for POST method?Can you share screenshot of the same? payload?

Former Member
0 Kudos

I have attached the following:

request1.png : initial request with X-CSRF-Token FETCH

request2.png : POST request

response2.png : POST response

Jitendra_Kansal
Product and Topic Expert
Product and Topic Expert
0 Kudos

From request2.png what i have noticed is, you are able to do a POST method through IGW service (https://smpserver:port/gateway/odata/xxxxx). Dont you want to do it via SMP application id? (for this you have to create an application id in Admin cockpit and have to whitelist IGW URL under "Backend" tab)

Is this your requirement? In general, you should on-board your device at SMP server first so that you can get an SMP APPCID on success, then you should do CRUD operation at backend level.

What is SMP 3.0 runtime/server SP version?

Former Member
0 Kudos

After making the necessary adjustments we did the following test:

settings0.png : application settings (back-end)

request1.png : initial request with X-CSRF-Token FETCH

request2.png : DELETE request

For clarification, we used a DELETE request because while being less complex than a PUT request it test a similar scenario (request for modification of back-end data). I would also like to add that while the DELETE functionality is not yet fully implemented on the ABAP side, we can confirm we were able to successfully receive it on the ERP side.

This being said, when testing the application, the DELETE request is not received by the ERP side, and, after last modifications, we aren't able to detect a 403 error anymore.

SAP Mobile Platform server version is 3.0.5.0, meaning SP05 PL01.

Jitendra_Kansal
Product and Topic Expert
Product and Topic Expert
0 Kudos

As you have tested DELETE operation functionality in REST Client.. i doubt something wrong in the code.

Let me call to hear from her.

claudiapacheco
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Valentin,

When you use the offlinestore, all the requests are sent to the local database, so the following methods are not accessing the SMP server, (only your local database). That's why it seems strange you are getting 403 forbidden when you call this methods.

  • ODataOfflineStore.scheduleCreateEntity
  • ODataOfflineStore.schedulePatchEntity or ODataOfflineStore.scheduleUpdateEntity
  • ODataOfflineStore.scheduleDeleteEntity

The offlinestore communicates with the server when you use the methods:

- ODataOfflineStore.flush() to send the local changes to the backend, and

- ODataOfflineStore.refresh() to update the local database with changes from the backend.

The offlinestore and the offline component on the SMP server take care of the X-CSRF-Token, so you don't need to do anything to handle the X-CSRF-Token from the app perspective (if you are using the offline store).

be patient, I may need to ask you more questions to understand your problem.

I'm confused because the explanation of your problem match the online store and not with the offline store.

Question1: Could you please clarify exactly when are you getting the errors?

- If it's when you call any of the CRUD methods (scheduleCreateEntity, scheduleUpdateEntity, etc), the problem is with your local database

- if it's when you call flush() or refresh()? -> then it's when the offline store is communicating with the server.

Question2: Just to double check, are you using the UsingOfflineAPI project from this git repository? SAP/sap_mobile_native_android · GitHub

Best regards

Claudia

Former Member
0 Kudos

Hello,

It is good we have confirmation that we do not need to handle the X-CSRF-Token from the application code, in our offline store scenario.

For clarification:

AnswerToQuestion1: We are getting the error when calling the flush() method. It is our understanding that scheduleCreateEntity(), scheduleUpdateEntity(), schedulePatchEntity(), scheduleDeleteEntity() operate on the offline store and a ODataOfflineStore.flush() method is required to communicate the changes to the back-end. There is no error or exception on the mobile application side, the 403 error was detected in the SMP server logs. However, after making some modifications of the application configurations on the SMP server (settings0.png in the above post) we were unable to detect the 403 error anymore. As the situation stands at the moment, when calling ODataOfflineStore.flush() there is no error on the mobile application side, no error on the SMP server side, but no communication reaches the SAP ERP back-end either.

AnswerToQuestion2: Yes, we are indeed using SAP/sap_mobile_native_android at solution · GitHub as template. However our setup is different as we did not use the MAFLogon component. We developed custom user on-boarding/registration following as template.

Thank you.

Regards,

~ Valentin Alexandru Tudorache

claudiapacheco
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Valentin,

Let's try to discard problems with the credentials.

I missed one thing in this How To... On-board users with SMP 3.0 OData SDK (Android) guide. If you are using the LogonCore class to register the user with SMP, when the registration finishes and if it is successful, you need to call a method in the LogonCore class that is called persistRegistration. This method stores the data from the logon context to the data vault.

With the credentials persisted, you would need to implement the UsernamePasswordProvider interface. I believe there's a sample of this class in the project you downloaded from SAP/sap_mobile_native_android at solution · GitHub It should be in the online package and it's called "CredentialsProvider.java". let me know if you cannot find it.

Currently the UsingOfflineAPI sample app configures the HTTPConversationManager with the LogonConfigurator. This is valid ONLY when you are using MAF Logon component

  IManagerConfigurator configurator = LogonUIFacade.getInstance().getLogonConfigurator(context);

  HttpConversationManager manager = new HttpConversationManager(context);

  configurator.configure(manager);

You are not using MAF Logon component, so you would need to configure the HTTPConversationManager with your custom UsernamePasswordProvider class.

For example:

CredentialsProvider credProvider = CredentialsProvider.getInstance(lgCtx);

             HttpConversationManager manager = new CommonAuthFlowsConfigurator(context).supportBasicAuthUsing(credProvider).configure(new HttpConversationManager(context));

  ODataOfflineStoreOptions options = new ODataOfflineStoreOptions();

  options.host = url.getHost();

  options.port = String.valueOf(url.getPort());

  options.enableHTTPS = lgCtx.isHttps();

  options.serviceRoot= endPointURL;

  options.conversationManager = manager;

...

Question3: How are you opening the offlinestore?


Suggestion: Another thing you can try is to look for synchronization errors. There are 2 ways to detect errors during flush:

1. errors are recorded in the ErrorArchive, which is returned to the client device as an OData feed. The application can obtain the body of the original request and allow the user to re-submit the operation.

2. The application receives notification of these errors through the Request Failure Listener (Android).


Please have you look at this guide that explains how to access errors during synchronization

Best regards

Claudia

Former Member
0 Kudos

Hello,

Yes, we realized that the above mentioned example lacks a persistence component, and we did solve it by calling LogonCore.persistRegistration() and LogonCore.persistDV() on the registrationFinished() method of the implemented LogonCoreListener.

Now, when moving on to the step where we needed to open the store, with regards to the HTTPConversationManager, we did the following:


HttpConversationManager managerHTTPConversation = new HttpConversationManager(context);

CommonAuthFlowsConfigurator configuratorCommonAuthFlows = new CommonAuthFlowsConfigurator(context);

UsenamePasswordProvider providerUsernamePassword = new UsernamePasswordProvider() {

     public Object onCredentialsNeededUpfront(ISendEvent event) {

          return new UsernamePasswordToken(..., ...);

     }

     public Object onCredentialsNeededForChallenge(IReceiveEvent event) {

          return new UsernamePasswordToken(..., ...);

     }

}

configuratorCommonAuthFlows.supportBasicAuthUsing(providerUsernamePassword);

configuratorCommonAuthFlows.configure(managerHTTPConversation);

optionsODataOfflineStore.conversationManager = managerHTTPConversation;

AnswerToQuestion3: We open the offline store using the ODataOfflineStoreOptions object (with regards to the above, for the HttpConversationManager).

With regards to synchronization errors, we have implemented the ODataRequestListener, but the ODataOfflineStore.flush() does not trigger the requestFailed() method. Rather, the responses we get from the listeners are ODataRequestListener.requestFinished() and ODataOfflineStoreFlushListener.offlineStoreFlushSucceeded().

Thank you.

Regards,

~ Valentin Alexandru Tudorache

claudiapacheco
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Valentin,

Your code looks ok.

Question4:  can you attached in a txt with the complete code that you use to open the offline store for my review?

You mentioned you have SMP 3.0 SP05 PL01 server, which is the latest.

Question5: could you please confirm you are using the latest SDK install. SDK 3.0 SP06 PL02 (I think)?

After a flush, you should do a refresh.

Question 6: if something changes in the odata producer, does the changes are reflected in the app when you do the refresh?

Best regards

Claudia

Former Member
0 Kudos

Hello,

Answer to Question 4: I have attached the ODataOfflineStoreManager.offlineStoreOpen() method that we use for opening the offline store (please see offlineStoreOpen().txt).

Answer to Question 5: Yes, we are currently using SAP Mobile Platform 3.0 server SP05 PL01. At the time the current thread was open we were using (and still are using) SAP Mobile Platform SDK 3.0 SP06 PL01. We are aware PL02 is available for the SDK but are yet to upgrade the libraries, as we did not consider the upgrade compulsory for solving our current issue. We will upgrade a.s.a.p and get back with comments (if anything changes).

Answer to Question 6: As things stand with our current scenario, for testing purposes, we isolated the offline store modifying methods (such as scheduleCreateEntity(), scheduleUpdateEntity(), scheduleDeleteEntity()) from the flush() and refresh() methods. In adition to the above we have a getAllEntities() that returns (from the local offline store) the list of entities. Consequently, we first call a modifying method (let's say scheduleDeleteEntity()), then we call getAllEntities() (to verify if the change had occurred locally), then we call flush() (to communicate the changes to the server and back-end), then we call refresh() (to get the, hopefully, updated list).


When following the above steps, we get the following:

- scheduleDeleteEntity() is successful (according to the attached listener)

- getAllEntities() returns the original list without the deleted entity (which means the changes are successful on the local store)

- flush() is successful (according to the attached listener) but the ABAP code associated is not called in the SAP ERP back-end

- refresh() is successful (according to the attached listener) but all it does is return the store to the initial state (this is normal, as the change did not successfully reach the back-end)

Thank you.

Regards,

~ Valentin Alexandru Tudorache

claudiapacheco
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Valentin,

Correct me if I'm wrong, but I think you are missing the steps to detect synchronization errors, in your code snipped you are setting offlineStore.setOfflineStoreListener, which is a listener used to get progress updates while an ODataOfflineStore is opening.  You need to set ODataOfflineStoreRequestErrorListener, which is a listener used to get notifications about requests that failed against the backend OData Producer

Please have you look at this guide that explains how to access errors during synchronization How to... Handle Synchronization Errors (Android)

One method explained in this guide is using ODataOfflineStoreRequestErrorListener  :

1. Implement the ODataOfflineStoreRequestErrorListener interface and implement the method offlineStoreRequestFailed  -> if there are errors during synchronization, this method will be called.

2. Assign that listener to the offline store using offlineStore.setRequestErrorListener(errorlistener) after you open the store.

Another method is accessing the ErrorArchive collection. which is also explained in the guide.

With any of these changes you should be able to detect why the changes are not propagated to the backend.

Let me know

Claudia

Former Member
0 Kudos

Hello,

We have implemented the ODataOfflineStoreRequestErrorListener as follows:


private static class MyODataOfflineStoreRequestErrorListener implements ODataOfflineStoreRequestErrorListener {

     public void offlineStoreRequestFailed(ODataOfflineStore store, ODataRequestExecution execution, ODataException exception) {

          Log.d(TAG, " Start.offlineStoreRequestFailed()");

          if (execution != null && execution.getResponse() != null) {

               ODataPayload payload = ((ODataResponseSingle) execution.getResponse()).getPayload();

               if (payload != null && payload instanceof ODataError) {

                    ODataError oError = (ODataError) payload;

                    OfflineODataStoreException exceptionStore = new OfflineODataStoreException(oError.getMessage());

                    Log.d(TAG, " Start.offlineStoreRequestFailed() : error : " + exceptionStore);

               } else {

               Log.d(TAG, " Start.offlineStoreRequestFailed() : error : " + exception);

               }

          } else {

          Log.d(TAG, " Start.offlineStoreRequestFailed() : error : " + exception);

          }

       }

  }

When following the previously described testing scenario, when calling flush(), the listener returns the following exception:

com.sap.smp.client.odata.exception.ODataNetworkException: Unknown network response error occured


with the trace:



...

Caused by: com.sap.smp.client.odata.offline.ODataOfflineException: [-10197] A request failed against the backend OData producer - code: "", error: "", inner error: ""



Thank you.

Regards,

~ Valentin Alexandru Tudorache

claudiapacheco
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Valentin,

The the changes you made, we can confirm this is a problem on the server side trying to communicate with your odata producer. It may be related to the way you defined the application configuration. I was hoping the error would give you more details, but it does not provide much information.

Reviewing again your application configuration I noticed you marked the backend as "internal"

Defining Back-End Connections - Administrator - SAP Library

"Whitelist a service that you create in the mobile platform. If you define an endpoint as internal, the host name and port of the back-end URL are ignored, and incoming requests are forwarded to internal services in-process, without another HTTP call to localhost. An example of an internal service is Integration Gateway."

I wonder if this is part of the problem. do you still have this setting on?


I think you should open a ticket and provide more details of the IT landscape (proxy, etc) for the support team. Add as much information as possible.


Best regards

Claudia

Former Member
0 Kudos

Hello,

Regarding the Internal setting on the application configuration, yes, we currently do have it on.

While we are not 100% sure about the implications, but since the current application configuration works (all CRUD operations) when testing from a REST client, is it still safe to assume our problem is on the above mentioned server-side application configuration? If so, we will proceed in opening a support ticket as suggested.

Thank you.

Regards,

~ Valentin Alexandru Tudorache

claudiapacheco
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Valentin,

When you test from the REST client, you are testing the online functionality. My guess is that the offline component of the server is having problems connecting to your integration gateway service. It's just a guess, so we need the support team to take a closer look at your IT landscape. Please proceed with the ticket and keep us inform of any progress. I'm sure the community will benefit from your experience.

Thanks

Claudia

0 Kudos

Hello Valentin,


Hope you resolved this - I am curious to know if the problem was related your authentication provider/SSO mechanisms on the server. I have tried stacking SSO Mechanisms in SMP 3.0 server and have found it can get difficult!