I recently came on board with The University of Mississippi Office of Information Technology with the task to deliver an iPad app consuming SAP data via NetWeaver Gateway (NG) in little more than a month. Most of my time was spent getting up to speed on Cocoa (I hadn’t worked directly in Objective-C for over a year) and developing the user interface. The backend was pretty much complete providing data to pre-existing portal (EP) based applications, and other developers were tasked with creating the NG Data and Consumption models. From my perspective as the app developer, NG provided a simple to use mechanism to access data from SAP.
Our application is targeted at Admissions Counselors who travel the U.S. to meet with prospective high-school students and others interested in attending The University of Mississippi.
When I came on board they had a prototype application built using proxy classes generated using the SAP NetWeaver Gateway developer tool for Xcode1. Although incomplete this prototype was successfully pulling data from SAP into native Cocoa objects and plugging them into some UITableViews.
In order to quickly deploy our application we wanted to ensure that existing portal-bound applications could also be accessible. Additionally the counselors wanted to be able to search for students by attributes or by the school they were visiting that day. These requirements led me to utilize a tab-based root view (UITabBarController) with four view modes: home view (guide buttons to the other tabs, and various website links), student search, school search, and web view. The UIWebView on the fourth tab would provide a built-in, general purpose web-browser as well as a pre-defined view for the various portal-bound pages linked from the student details.
The first major hurdle to tackle was authentication. Much of this was before my role in the project, but we settled on a solution of collecting credentials from the user and submitting them to a post action on our portal server to establish a cookie. Delightfully, all NSURLConnection based operations (UIWebView among them) share browser cookie storage so we were able to seamlessly log the user into our application as well as the portal-bound pages in one operation.
One issue we encountered is that the portal sign-in expects a supported user-agent so we had to set that header manually on the login request since we’re using a raw NSURLConnection. The data service queries also required injecting headers (the portal cookie) but this process was very straight-forward as I’ll cover below.
The proxy classes generated by the SAP NetWeaver Gateway developer tool for Xcode1 utilize the OData Client for Objective-C to consume the gateway provided services. Requesting a collection of data is fairly straightforward: create the proxy for the service, execute the query and store the response. This example collects a list of US states from our ADMISSIONSCOUNSELOR consumption model. Once the response is loaded, the result is fetched as a native NSArray of states:
Other than the fact that the consumption model naming conventions yield “strange” (to Objective-C developers) class and property names, the results are native Objective-C objects ready to be used in your app. Astute readers will recognize that this process is NOT asynchronous, I’ll cover that in the next section.
Filtering a query is also straight-forward:
This example demonstrates several typical argument types you may encounter as well as an example of the properties generated by the tool i.e. selectedStatus.m_value.
OData SDK Shortcomings
OData queries run as synchronous operations and don’t share the application’s NSURLConnection cookie storage. I’m not sure what mechanism the SDK is using but it’s curious that the developers seemingly avoided the readily available asynchronous mechanisms.
In the app prototype, queries were being run on the main thread which resulted in the UI being blocked during query execution. To combat this blocking I utilized multi-threading within the application to spawn the queries off the main thread so the interface could remain responsive. Thankfully Apple provides a very simple multi-threading solution in NSOperationQueue, however despite its simplicity, this approach required me add code to ensure that UI operations (stopping the activity indicator, updating the results table, etc.) would be performed on the main thread.
An additional side-effect of the synchronous query model is that connection errors such as timeouts are thrown as exceptions (as opposed to NSURLConnection’s connection:didFailWithError: method). To address this short-coming I wrapped the query operation in a try block:
Since updating the table view’s data is essentially a UI operation, this needs to be done on the main thread. Originally I updated the data in the loadStates method, however this produced several second delays in updating the interface.
Lastly, the OData SDK query/connection timeout period is set at 30 seconds. For NSURLConnection you can specify a longer timeout, however 30 seconds is reasonable and most of our issues with timeouts ideally need to be addressed in the backend code that’s collecting the data for NG.
Our experience as NetWeaver Gateway early adopters has been very positive. Consuming the services from iOS has been simple and, other than some issues with how the OData SDK is written, it allows fairly quick turn-around for getting data from SAP into Cocoa.
1Please note that the SAP NetWeaver Gateway developer tool for Xcode is no longer available. You can instead use the generator tool (ODataGen) included with the OData SDK at odataobjc.codeplex.com.