© 2013 SAP AG or an SAP affiliate company. All rights reserved. 1
SAP Mobile - Webinar Series Developing mobile apps with SMP SDK for Android Claudia Pacheco Customer Experience Group (CEG) SAP
Brought to you by the Customer Experience Group
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 2
Agenda
SAP Mobile Platform 3.0 � Architecture Overview
On Boarding users with MAF � Overview and Code Snipped
Harmonized OData API � Overview � Online � Offline
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 3
SAP Mobile Platform 3.0 Architecture Overview
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 4
Agenda
SAP Mobile Platform 3.0 � Architecture Overview
On Boarding users with MAF � Overview and Code Snipped
Harmonized OData API � Overview � Online � Offline
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 5
Create Application Connection POST [/public]/odata/applications/{v1|latest}/{appName}/Connections Read Application Settings GET [/public]/odata/applications/{v1|latest}/{appName}/Connections(‘{appcid}') GET [/public]/odata/applications/{v1|latest}/{appName}/Connections(‘{appcid}')/{prop} Delete Application Connection DELETE [/public]/odata/applications/{v1|latest}/{appName}/Connections(‘{appcid}') Download Application Resource Bundle GET [/public]/bundles/{appName}/{resourceBundleName:Version} …..
Client can register in SMP via HTTP
commands. – no platform specific SDK
libs required.
Note: the data format is OData (v1) but no query function (ex. $filter)
What is user on-boarding? “User on-boarding is the process of registering a user and giving them appropriate access to data and applications.”
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 6
On Boarding users with MAF Steps to Implementing MAF Login Component
The MAF Login Component is very simple to implement with only a few lines of code needed.
First, create an Activity that implements the LogonListener interface. � In the create() method:
– Get an instance of the singleton class LogonUIFacade. – Initialize the instance by calling the init(…) method. – Set the content view to be the MAF logon screen. – That’s it!
� After logon is complete method onLogonFinished(…) is called. – Check if the logon was successful. – Load main screen.
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 7
On Boarding users with MAF Implementing MAF Logon Component - Code
public class MAFLogonActivity extends Activity implements LogonListener { ... @Override protected void onCreate(Bundle savedInstanceState) { ... // Get the Instance of the LogonUIFacade, Initialize it, set the Content View mLogonUIFacade = LogonUIFacade.getInstance(); mLogonUIFacade.init(this, mContext, mSmpAppId); setContentView(mLogonUIFacade.logon()); ... } @Override public void onLogonFinished(String message, boolean isSuccess,LogonContext lgContext) { if (isSuccess) { // Optionally you can gather information from the registration String appConnID = LogonCore.getInstance().getLogonContext().getConnId(); String username = lgContext.getEndPointUser(); String password = lgContext.getEndPointPassword(); String endpointURL = lgContext.getEndPointUrl(); ... // Navigate to the Main menu screen Intent goToNextActivity = new Intent(this, MainActivity.class); startActivity(goToNextActivity); finish(); } } …
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 8
Agenda
SAP Mobile Platform 3.0 � Architecture Overview
On Boarding users with MAF � Overview and Code Snipped
Harmonized OData API � Overview � Online � Offline
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 9
Harmonized OData API Overview
Provide a developer friendly API that � Is focused on the OData interface
� Hides OData implementation details such as: – Fetching the OData service document and metadata – No need to worry about assembling OData results (e.g. parsing ATOM/XML or JSON) – Mapping of OData data types to native objects
� Supports both online and offline access
� Supported devices: iOS, Android, Win8
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 10
Application
ODataAPI lib
Online Store Offline Store
Parser Request Parser
ODataStore lifecycle API ODataStore lifecycle API
Mobilink
ODataStore API (send/recv OData req: CREATE, READ, ...)
Payload API (Entity, Feed, ...)
Metadata API (serviceDoc, metadata)
Harmonized OData API Online and Offline Store
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 11
Harmonized OData API Open Online Store
LogonCoreContext lgCtx = LogonCore.getInstance().getLogonContext();//The logon configurator uses the information obtained in the registration (i.e endpoint URL, login, etc )// to configure the conversation manager IManagerConfigurator configurator = LogonUIFacade.getInstance().getLogonConfigurator(context);HttpConversationManager manager = new HttpConversationManager(context);configurator.configure(manager);//XCSRFTokenRequestFilter implements IRequestFilter Request filter that is allowed to preprocess the request before sending XCSRFTokenRequestFilter requestFilter = XCSRFTokenRequestFilter.getInstance(lgCtx);XCSRFTokenResponseFilter responseFilter = XCSRFTokenResponseFilter.getInstance(context, requestFilter);manager.addFilter(requestFilter);manager.addFilter(responseFilter);
try { URL url = new URL(lgCtx.getAppEndPointUrl()); //options OnlineStoreOptions onlineOptions = new OnlineStoreOptions(); onlineOptions.format = PayloadFormatEnum.JSON; //Method to open a new online store OnlineODataStore.open(context, url, manager, openListener, onlineOptions); openListener.waitForCompletion(); if (openListener.getError() != null) {
AgencyLogManager.writeLogError("openOnlineStore", openListener.getError());throw openListener.getError();
}} catch(Exception e){ throw new AgencyOnlineException(e);}
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 12
Harmonized OData API GET Request
//Executor method for reading an Entity set synchronouslyODataResponseSingle resp = store.executeReadEntitySet(Collections.TRAVEL_AGENCY_COLLECTION + "?$orderby="+Collections.TRAVEL_AGENCY_ENTRY_ID+"%20desc", null);//Get the response payloadODataEntitySet feed = (ODataEntitySet) resp.getPayload();//Get the list of ODataEntityList<ODataEntity> entities = feed.getEntities();AgencyLogManager.writeLogDebug("getAgencies::get list of agencies:"+entities.size());for (ODataEntity entity: entities){ ODataPropMap properties = entity.getProperties(); ODataProperty property = properties.get(Collections.TRAVEL_AGENCY_ENTRY_ID); Agency agency = new Agency((String)property.getValue()); property = properties.get(Collections.TRAVEL_AGENCY_ENTRY_NAME); agency.setAgencyName((String)property.getValue()); property = properties.get(Collections.TRAVEL_AGENCY_ENTRY_STREET); agency.setStreet((String)property.getValue()); property = properties.get(Collections.TRAVEL_AGENCY_ENTRY_CITY); agency.setCity((String)property.getValue()); property = properties.get(Collections.TRAVEL_AGENCY_ENTRY_COUNTRY); agency.setCountry((String)property.getValue()); property = properties.get(Collections.TRAVEL_AGENCY_ENTRY_URL); agency.setWebsite((String)property.getValue());
agency.setEditResourceURL(entity.getEditResourcePath());
agencyList.add(agency);}
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 13
Harmonized OData API Payload
//Use default implementation to create a new travel agency entity typeODataEntity newEntity = new ODataEntityDefaultImpl(Collections.TRAVEL_AGENCY_ENTITY_TYPE);//If available, it will populates those properties of an OData Entity //which are defined by the allocation mode store.allocateProperties(newEntity, PropMode.All);//If available, it populates the navigation properties of an OData Entitystore.allocateNavigationProperties(newEntity);//Set the corresponding propertiesnewEntity.getProperties().put(Collections.TRAVEL_AGENCY_ENTRY_ID,
new ODataPropertyDefaultImpl(Collections.TRAVEL_AGENCY_ENTRY_ID, agency.getAgencyId()));newEntity.getProperties().put(Collections.TRAVEL_AGENCY_ENTRY_NAME,
new ODataPropertyDefaultImpl(Collections.TRAVEL_AGENCY_ENTRY_NAME, agency.getAgencyName()));newEntity.getProperties().put(Collections.TRAVEL_AGENCY_ENTRY_STREET,
new ODataPropertyDefaultImpl(Collections.TRAVEL_AGENCY_ENTRY_STREET, agency.getStreet()));newEntity.getProperties().put(Collections.TRAVEL_AGENCY_ENTRY_CITY,
new ODataPropertyDefaultImpl(Collections.TRAVEL_AGENCY_ENTRY_CITY, agency.getCity()));newEntity.getProperties().put(Collections.TRAVEL_AGENCY_ENTRY_COUNTRY,
new ODataPropertyDefaultImpl(Collections.TRAVEL_AGENCY_ENTRY_COUNTRY, agency.getCountry()));newEntity.getProperties().put(Collections.TRAVEL_AGENCY_ENTRY_URL,
new ODataPropertyDefaultImpl(Collections.TRAVEL_AGENCY_ENTRY_URL, agency.getWebsite()));
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 14
Harmonized OData API Payload
Odata Types Java Types
Edm.Int64 Long
Edm.Int32 Integer
Edm.Decimal BigDecimal
Edm.String String
Edm.DateTime Calendar
Edm.Time com.sap.smp.client.odata.impl.ODataDurationDefaultImpl
Mapping of Odata data types to native objects
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 15
Harmonized OData API POST and PUT request
//The travel agency entity to be createdODataEntity newEntity = createAgencyEntity(store, agency);//AgencyRequestListener implements ODataRequestListener, // which receives the response from the server and notify the activity that // shows the message to the userAgencyRequestListener agencyListener = new AgencyRequestListener(Operation.CreateAgency.getValue(), uiListener);//Scheduling method for creating an Entity asynchronouslystore.scheduleCreateEntity(newEntity, Collections.TRAVEL_AGENCY_COLLECTION, agencyListener, null);
//The travel agency entity to be updatedODataEntity newEntity = createAgencyEntity(store, agency);//AgencyRequestListener implements ODataRequestListener, // which receives the response from the server and notify the activity that // shows the message to the userAgencyRequestListener agencyListener = new AgencyRequestListener(Operation.UpdateAgency.getValue(), uiListener);//Scheduling method for updating an Entity asynchronouslystore.scheduleUpdateEntity(newEntity, Collections.TRAVEL_AGENCY_COLLECTION, agencyListener, null);
POST Request
PUT Request
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 16
Harmonized OData API DELETE request
//AgencyRequestListener implements ODataRequestListener, // which receives the response from the server and notify the activity that // shows the message to the userAgencyRequestListener agencyListener = new AgencyRequestListener(Operation.DeletAgency.getValue(), uiListener);//Scheduling method for deleting an Entity asynchronouslystore.scheduleDeleteEntity(agency.getResourcePath(), null, agencyListener, null);
DELETE Request
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 17
Harmonized OData API ODataRequestListener
ODataRequestListener Methods Listener for asynchronous OData operations, its various methods are invoked at key events
Method Description
requestStarted(ODataRequestExecution req) Request has been started
requestCacheResponse(ODataRequestExecution req) Cache response has been received
requestServerResponse(ODataRequestExecution req) Server response has been received
requestFailed(ODataRequestExecution req, ODataException exception)
Odata request has failed
requestFinished(ODataRequestExecution req) Odata request finished
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 18
Harmonized OData API ODataRequestListener
@Overridepublic void requestFailed(ODataRequestExecution request, ODataException e) { //Verify request is not null if (request!=null && request.getResponse() !=null) { //Get payload message from server ODataPayload payload = ((ODataResponseSingle) request.getResponse()).getPayload();
//Parse the error from the server if (payload!=null && payload instanceof ODataError) {
ODataError oError = (ODataError) payload;TraceLog.d("requestFailed - status message " + oError.getMessage());//Notify the activity of this eventnotifyErrorToListener(new OnlineODataStoreException(oError.getMessage()));return;
} } notifyErrorToListener(e);}
requestFailed method
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 19
Harmonized OData API ODataRequestListener
@Overridepublic void requestServerResponse(ODataRequestExecution request) { //Verify request is not null if (request!=null && request.getResponse() !=null) {
//Parse the responseODataResponseSingle response = (ODataResponseSingle) request.getResponse();//Get the http status codeMap<Headers, String> headerMap = response.getHeaders();String code = headerMap.get(Headers.Code);TraceLog.d("requestServerResponse - status code " + code);//Get payload, for some cases (POST request) server returns the agency createdODataPayload payload = ((ODataResponseSingle) request.getResponse()).getPayload();if (payload!=null && payload instanceof ODataEntity) { ODataEntity oEntity = (ODataEntity) payload;
ODataPropMap properties = oEntity.getProperties(); ODataProperty property = properties.get(Collections.TRAVEL_AGENCY_ENTRY_ID); //Notify the activity of this event notifySuccessToListener((String)property.getValue()); return;}
} notifySuccessToListener(null);}
requestServerResponse method
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 20
Overview
Mobile Client
LOData
UltraLiteDatabase
SMP Client SDK
Application(Native or UI5)
R
OData
SQL
Mobile Services
Dispatcher
Optimized Offline OData Transport
OData Proxy Integration Gateway
Mobilink
MOData
Mobilink(Relational Protocol)
OData OData
OData Producer 3rd Party
OData JPA / JDBC / Web Services
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 21
Initial Download Sequence
Mobile App Optimized Offline OData Transport
OData Producer
Database Filename
Request Initial Download(seed URLs)
return
Request Metadata
Initialize Database
For each Seed URL
Data
Request Data
Populate Database
If not Delta Enabled
Cache Keys
File download
Request Database
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 22
Harmonized OData API Open Offline Store
//This instantiate the native UDB libraries which are located in the libodataofflinejni.so fileODataOfflineStore.globalInit();LogonCoreContext lgCtx = LogonCore.getInstance().getLogonContext();String endPointURL = lgCtx.getAppEndPointUrl();URL url = new URL(endPointURL);// Define the offline store options. // Connection parameter and credentials and the application connection id we got at the registrationODataOfflineStoreOptions options = new ODataOfflineStoreOptions();
options.host = url.getHost();options.port = String.valueOf(url.getPort());options.enableHTTPS = lgCtx.isHttps();options.serviceRoot= endPointURL;
IManagerConfigurator configurator = LogonUIFacade.getInstance().getLogonConfigurator(context);HttpConversationManager manager = new HttpConversationManager(context);configurator.configure(manager);… options.conversationManager = manager;
options.storeName="flight";
//This defines the oData collections which will be stored in the offline storeoptions.definingRequests.put("reg1", Collections.TRAVEL_AGENCY_COLLECTION);
//Open offline storeofflineStore = new ODataOfflineStore(context);offlineStore.openStoreSync(options);
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 23
Request for Refresh Sequence
Mobile App Optimized Offline OData Transport
OData Producer
Data
Request for Refresh(seed URLs)
For each Seed URL If Delta Enabled
Retrieve Keys from Cache
Data
Request Data with delta token
If not Delta Enabled
Data
Request Data
Compute Delta
Transform all changes to relational / Mobilink protocol
Apply changes to Database
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 24
Harmonized OData API Refresh Operation
//AgencyRefreshListener implements ODataOfflineStoreRefreshListenerAgencyRefreshListener refreshListener = new AgencyRefreshListener(uiListener);//Asynchronously refreshes the store with the OData serviceofflineStore.scheduleRefresh(refreshListener);
Refresh Operation
ODataOfflineStoreRefreshListener Methods Listener that receives progress updates of a refresh operation. Its various methods are invoked at key events
Method Description offlineStoreRefreshFailed(ODataOfflineStore, ODataException)
Refresh operation has failed
offlineStoreRefreshFinished(ODataOfflineStore) Refresh operation has finished offlineStoreRefreshStarted(ODataOfflineStore) Refresh operation started offlineStoreRefreshSucceeded(ODataOfflineStore) Refresh operation succeded
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 25
Mobile App Optimized Offline OData Transport
OData Producer
Update DB to reflect pending change
OfflineCreate, Update or Delete Data
Request (POST, PUT, PATCH, BATCH) added to Request Queue
All errors along with their original requests are stored in the Error Archive
Online
Etags are checked for potential conflicts
Errors & Successes (Etags, Location Headers)
Process Request Queue
For each Request
Response
Request
Request for Refresh
See Request for Refresh Sequence
Delete local change from DB
Queries on data reflect pending updates
Local Updates Sequence
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 26
Harmonized OData API Flush Operation
//AgencyFlushListener implements ODataOfflineStoreFlushListenerAgencyFlushListener flushListener = new AgencyFlushListener(uiListener);//Asynchronously starts sending pending modification request to the serverofflineStore.scheduleFlushQueuedRequests(flushListener);
Flush Operation
ODataOfflineStoreFlushListener Methods Listener that receives progress updates of a flush operation. Its various methods are invoked at key events
Method Description offlineStoreFlushFailed(ODataOfflineStore, ODataException)
Flush operation has failed
offlineStoreFlushFinished(ODataOfflineStore) Flush operation has finished offlineStoreFlushStarted(ODataOfflineStore) Flush operation started offlineStoreFlushSucceeded(ODataOfflineStore) Flush operation succeded
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 27
Harmonized OData API Conflict Resolutions
ETag The ETag or entity tag is part of HTTP. It is one of several mechanisms that HTTP provides for web cache validation, and which allows a client to make conditional requests
The behavior of the conflict handling is determined by the backend OData producer There are two modes: � If the OData Producer supports ETags:
– An error will be thrown when a user tries to overwrite another user’s changes.
� If the Odata Producer does NOT support Etags: – The last one wins policy will be in effect
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 28
Harmonized OData API Error Handling
Error Handling During a flush, the offline store communicates with the server and attempts to execute all of the stored requests against the OData Producer. If the OData Producer fails one of the queued requests during a flush, the client is notified in two ways: � If the requestErrorListener property of the offline store is set, then the listener method is called. � By querying the contents of the error archive The error archive is exposed to the application as an OData collection and is accessible through OData read requests to the URL /ErrorArchive. The error archive must be cleared out by the application by executing DELETE requests against the individual entries in the error archive.
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 29
Harmonized OData API Offline OData Version Support
OData version 2 is supported for the offline OData feature, with several exceptions. � There is no support for these OData concepts
– Function imports. – Media resources. – Deep inserts. – ETags when using the if-match/if-none-match headers when performing LOCAL reads. – Modifying properties or complex type properties by addressing them in the URL. – Metadata annotations are not populated in the Metadata object.
� The Offline OData feature has the following limitations: – The maximum length (MaxLength) of Edm.String key properties is 512 characters. – The maximum length (MaxLength) of Edm.Binary key properties is 1536 bytes.
Offline OData Version support
© 2013 SAP AG or an SAP affiliate company. All rights reserved. 30
SAP Mobile Platform 3.0 Enablement
SCN is our chosen channel to publish all information that you need to successfully install and run the "SAP Mobile Platform 3.0. On our Enablement Pages, you find links to White Papers, How-To Guides, Blogs and other resources:http://scn.sap.com/docs/DOC-49476 Webinars complement these published resources:"http://scn.sap.com/docs/DOC-55282
© 2014 SAP SE or an SAP affiliate company. All rights reserved. 43 Public
© 2014 SAP SE or an SAP affiliate company.
All rights reserved.
No part of this publication may be reproduced or transmitted in any form or for any purpose without the express permission of SAP SE or an
SAP affiliate company.
SAP and other SAP products and services mentioned herein as well as their respective logos are trademarks or registered trademarks of SAP SE
(or an SAP affiliate company) in Germany and other countries. Please see http://global12.sap.com/corporate-en/legal/copyright/index.epx for additional
trademark information and notices.
Some software products marketed by SAP SE and its distributors contain proprietary software components of other software vendors.
National product specifications may vary.
These materials are provided by SAP SE or an SAP affiliate company for informational purposes only, without representation or warranty of any kind,
and SAP SE or its affiliated companies shall not be liable for errors or omissions with respect to the materials. The only warranties for SAP SE or
SAP affiliate company products and services are those that are set forth in the express warranty statements accompanying such products and
services, if any. Nothing herein should be construed as constituting an additional warranty.
In particular, SAP SE or its affiliated companies have no obligation to pursue any course of business outlined in this document or any related
presentation, or to develop or release any functionality mentioned therein. This document, or any related presentation, and SAP SE’s or its affiliated
companies’ strategy and possible future developments, products, and/or platform directions and functionality are all subject to change and may be
changed by SAP SE or its affiliated companies at any time for any reason without notice. The information in this document is not a commitment,
promise, or legal obligation to deliver any material, code, or functionality. All forward-looking statements are subject to various risks and uncertainties
that could cause actual results to differ materially from expectations. Readers are cautioned not to place undue reliance on these forward-looking
statements, which speak only as of their dates, and they should not be relied upon in making purchasing decisions.