In this series of blog entries we will describe the development of a mobile chat app using SAP NetWeaver HANA Cloud as a backend. The last time Julia and Johannes explained how they enabled user authentication for our app. Now we want to give you an overview how we continued the development of this app and focus especially on the parts which are related to HANA Cloud.
Julia and Johannes did an excellent job building a Mobile Chat App and the corresponding backend totally from scratch. Our goals now are to re-design the iOS App, create a cross-platform Web App and to refactor the backend so that it is a platform which can be easily used by developers as API to develop chat clients on other devices and operating systems. Our highest priority is to keep conversations in sync with all our devices. This requires changes in the backend as well as on the iOS App.
Since Julia's and Johannes' internship at SAP is finished the project was taken over by sanket.firodiya and shofmann. Sanket is a SAP employee, focusing on the iOS App while I as an intern am developing a HTML5 WebApp from scratch. Together we are refactoring the backend to offer more functionality and make it more open for developers and different kind of platforms. Like Julia and Johannes did before we want to share our experiences with HANA Cloud.
By the way, we also changed the name of our project. To memorize the name easier (and actually to honor the inventors of the telegraph) we call it Wire :smile:
We introduced a new, sleek navigation to the iOS app using the open source framework ViewDeck. This navigation approach is used by many top iOS apps such as Facebook, Path etc. and we thought it would be a good fit for Wire.
The user authentication now uses native SAML2 authentication instead of the previous approach of using webviews. This has lead to increased performance and also helps in debugging the authentication process better.
The Chatroom model in Core Data now has a flag to indicate whether there are unread messages in it, which is used to display chatrooms differently depending on whether they are read or unread. Chatrooms also store the latest message timestamp in them, so its easier to arrange the chatrooms in the view based on the timestamp of their messages.
One major performance drain we saw in the earlier version of the app was that we were refreshing all messages in a chatroom everytime a new message arrives. We changed that and started maintaining unique ids for messages and retrieveing only the latest messages from the server, everytime a chatroom is refreshed.
This means that a chatroom with even hundreds of messages loads much faster now since it gets almost all its messages from the Core Data store. Also, the chatroom does not have to continously ping the server to get the latest messages. The chat room is notified by the Application Delegate when it receives a remote notification from APNS and the chatroom can request the latest messages from the server only if it is currently the view for the main window of the app.
We build our Web App on top of SAPUI5, a HTML5-based front-end framework from SAP which helps you to build great desktop and mobile web apps. To abstract the functionality of our web-service we build an isolated Service-module within our SAPUI5 app. In technical terms this is just one single Javascript file which can be included into any view or controller where we need it. After including it we just can call our methods we need, this looks for example like this:
m.util.Service.updateChatroomModel();
After calling a method the Service takes care of the communication. We're using SAPUI5's EventBus to notify the UI once a request is finished and we got a response from the backend. This helps us to make the UI independent from the communication with the backend. This gives us a big advantage: If the webservice changes and the way how we have to communicate with the backend we don't have to rewrite the whole WebApp, but only change the service-module - the abstracted methods inside the WebApp stay the same.
We faced the problem that pulling chat-messages from the server sometimes causes the WebApp to lag and freeze for half a second, even if we handle our requestes asynchronously. So we implemented HTML5 WebWorkers in our Service-module. Everytime the service wants to send an request to the backend, the service is delegating this request to a WebWorker which is running on a another thread. The WebWorker makes the requests, is waiting for the response and is passing the response back as a JSON object. The result is a really fluid HTML5 App.
Our first approach was to implement the Web App as a separate Java Web project which is also running on HANA cloud so it is detached from the backend. Doing it this way the backend and the Web App are running on 2 different domains. Even if we are hosting both applications on HANA cloud the subdomain is different. If we then want to to an AJAX call to the backend we violate the Same origin policy concept and the browser restricts the connection with the backend.
Because of that problem our second approach was to run the Web App inside the same web project as the backend is running in. This solves the Same origin policy problem but faces us with the fact that every time we want to deploy a new version of the Web App we will have to deploy the whole backend again. To avoid this problem in the future we want to split the backend and the Web App apart again but then want to use CORS - Cross-origin resource sharing. This mechanism allows us to make XmlHttpRequests to another domain without violating the Same origin policy.
So for now both, the iOS App as well as the Web App are communicating with HANA Cloud by using a RESTful webservice via HTTP. This webservice is based on a request-response-architecture. To detect if there are new messages in a chatroom we currently have two different approaches:
And there is the problem.
Just imagine if this Chat App is used by several thousand people in an organization and every app that is running is sending HTTP requests every 2.5 seconds, only to check if there are new messages in a chatroom. And the server always has to respond, even if there are no new messages at all. This causes a lot of traffic and overhead. We could now try to tune our application by minimizing the requests, but this reduces only the traffic - we still would have to face a lot of requests on the backend. We could also reduce the amount of requests by just extending the interval how often an app checks for updates, but then it's not really real-time anymore. So we decided to take a look at HTML5 WebSocket which enables us to open a consistent connection with the backend which stays open over the whole time the client is running. This has a few advantages:
What we definitely have to consider in the future is how scalable WebSocket is when it comes to simultaneous open connections the server has to manage. Even if managing an idle connection is as less expensive as constantly setting up a new connection, it might be interesting how Tomcat handles these open connections, how much memory each connection consumes and most important: Where the limits are.
Currently we are implementing WebSocket on our backend. We have faced a few problems with WebSocket regarding to HANA Cloud (see this discussion) but hopefully find a way around it. Once WebSocket communication is working we have the opportunity to implement a lot of new features. Due to the increased performance and reduced delay enabled by WebSocket we could for example implement features like Write-Notification (showing "User is currently typing a message") or synchronizing conversations across running apps within milliseconds. We're also planning to do Performance Testing and try out to find the limits of the WebSocket-approach.
In the following blog post series we want to explain you parts of the mentioned topics such as the API (which can be used by other developers) as well as our approach using WebSocket in detail.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
13 | |
10 | |
10 | |
7 | |
7 | |
6 | |
5 | |
5 | |
5 | |
4 |